#include "hw/qdev-core.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-ui.h"
+#include "qapi/visitor.h"
#include "qemu/coroutine.h"
#include "qemu/fifo8.h"
#include "qemu/error-report.h"
TTY_STATE_CSI,
};
-typedef enum {
- GRAPHIC_CONSOLE,
- TEXT_CONSOLE,
- TEXT_CONSOLE_FIXED_SIZE
-} console_type_t;
-
struct QemuConsole {
Object parent;
int index;
- console_type_t console_type;
DisplayState *ds;
DisplaySurface *surface;
DisplayScanout scanout;
int gl_block;
QEMUTimer *gl_unblock_timer;
int window_id;
+ QemuUIInfo ui_info;
+ QEMUTimer *ui_timer;
+ const GraphicHwOps *hw_ops;
+ void *hw;
+ CoQueue dump_queue;
+
+ QTAILQ_ENTRY(QemuConsole) next;
+};
+
+OBJECT_DEFINE_ABSTRACT_TYPE(QemuConsole, qemu_console, QEMU_CONSOLE, OBJECT)
+
+typedef struct QemuGraphicConsole {
+ QemuConsole parent;
- /* Graphic console state. */
Object *device;
uint32_t head;
- QemuUIInfo ui_info;
- QEMUTimer *ui_timer;
+
QEMUCursor *cursor;
int cursor_x, cursor_y, cursor_on;
- const GraphicHwOps *hw_ops;
- void *hw;
+} QemuGraphicConsole;
+
+typedef QemuConsoleClass QemuGraphicConsoleClass;
+
+OBJECT_DEFINE_TYPE(QemuGraphicConsole, qemu_graphic_console, QEMU_GRAPHIC_CONSOLE, QEMU_CONSOLE)
+
+typedef struct QemuTextConsole {
+ QemuConsole parent;
- /* Text console state */
int width;
int height;
int total_height;
Chardev *chr;
/* fifo for key pressed */
Fifo8 out_fifo;
- CoQueue dump_queue;
+} QemuTextConsole;
- QTAILQ_ENTRY(QemuConsole) next;
-};
+typedef QemuConsoleClass QemuTextConsoleClass;
+
+OBJECT_DEFINE_TYPE(QemuTextConsole, qemu_text_console, QEMU_TEXT_CONSOLE, QEMU_CONSOLE)
+
+typedef struct QemuFixedTextConsole {
+ QemuTextConsole parent;
+} QemuFixedTextConsole;
+
+typedef QemuTextConsoleClass QemuFixedTextConsoleClass;
+
+OBJECT_DEFINE_TYPE(QemuFixedTextConsole, qemu_fixed_text_console, QEMU_FIXED_TEXT_CONSOLE, QEMU_TEXT_CONSOLE)
struct VCChardev {
Chardev parent;
- QemuConsole *console;
+ QemuTextConsole *console;
enum TTYState state;
int esc_params[MAX_ESC_PARAMS];
static bool cursor_visible_phase;
static QEMUTimer *cursor_timer;
-static void text_console_do_init(Chardev *chr);
static void dpy_refresh(DisplayState *s);
static DisplayState *get_alloc_displaystate(void);
-static void text_console_update_cursor_timer(void);
-static void text_console_update_cursor(void *opaque);
+static void qemu_text_console_update_cursor(void *opaque);
static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl);
static bool console_compatible_with(QemuConsole *con,
DisplayChangeListener *dcl, Error **errp);
+static QemuConsole *qemu_graphic_console_lookup_unused(void);
+static void dpy_set_ui_info_timer(void *opaque);
static void gui_update(void *opaque)
{
}
}
-static void vga_fill_rect(QemuConsole *con,
- int posx, int posy, int width, int height,
- pixman_color_t color)
+static void qemu_console_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
};
+ assert(surface);
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(QemuConsole *con,
- int xs, int ys, int xd, int yd, int w, int h)
+static void qemu_console_bitblt(QemuConsole *con,
+ int xs, int ys, int xd, int yd, int w, int h)
{
DisplaySurface *surface = qemu_console_surface(con);
+ assert(surface);
pixman_image_composite(PIXMAN_OP_SRC,
surface->image, NULL, surface->image,
xs, ys, 0, 0, xd, yd, w, h);
#include "vgafont.h"
-#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_COLOR_BLACK] = QEMU_RGB(0x00, 0x00, 0x00), /* black */
- [QEMU_COLOR_BLUE] = QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
- [QEMU_COLOR_GREEN] = QEMU_RGB(0x00, 0xaa, 0x00), /* green */
- [QEMU_COLOR_CYAN] = QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
- [QEMU_COLOR_RED] = QEMU_RGB(0xaa, 0x00, 0x00), /* red */
- [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
- [QEMU_COLOR_YELLOW] = QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
- [QEMU_COLOR_WHITE] = QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
+ [QEMU_COLOR_BLACK] = QEMU_PIXMAN_COLOR_BLACK,
+ [QEMU_COLOR_BLUE] = QEMU_PIXMAN_COLOR(0x00, 0x00, 0xaa), /* blue */
+ [QEMU_COLOR_GREEN] = QEMU_PIXMAN_COLOR(0x00, 0xaa, 0x00), /* green */
+ [QEMU_COLOR_CYAN] = QEMU_PIXMAN_COLOR(0x00, 0xaa, 0xaa), /* cyan */
+ [QEMU_COLOR_RED] = QEMU_PIXMAN_COLOR(0xaa, 0x00, 0x00), /* red */
+ [QEMU_COLOR_MAGENTA] = QEMU_PIXMAN_COLOR(0xaa, 0x00, 0xaa), /* magenta */
+ [QEMU_COLOR_YELLOW] = QEMU_PIXMAN_COLOR(0xaa, 0xaa, 0x00), /* yellow */
+ [QEMU_COLOR_WHITE] = QEMU_PIXMAN_COLOR_GRAY,
},
{ /* bright */
- [QEMU_COLOR_BLACK] = QEMU_RGB(0x00, 0x00, 0x00), /* black */
- [QEMU_COLOR_BLUE] = QEMU_RGB(0x00, 0x00, 0xff), /* blue */
- [QEMU_COLOR_GREEN] = QEMU_RGB(0x00, 0xff, 0x00), /* green */
- [QEMU_COLOR_CYAN] = QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
- [QEMU_COLOR_RED] = QEMU_RGB(0xff, 0x00, 0x00), /* red */
- [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
- [QEMU_COLOR_YELLOW] = QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
- [QEMU_COLOR_WHITE] = QEMU_RGB(0xff, 0xff, 0xff), /* white */
+ [QEMU_COLOR_BLACK] = QEMU_PIXMAN_COLOR_BLACK,
+ [QEMU_COLOR_BLUE] = QEMU_PIXMAN_COLOR(0x00, 0x00, 0xff), /* blue */
+ [QEMU_COLOR_GREEN] = QEMU_PIXMAN_COLOR(0x00, 0xff, 0x00), /* green */
+ [QEMU_COLOR_CYAN] = QEMU_PIXMAN_COLOR(0x00, 0xff, 0xff), /* cyan */
+ [QEMU_COLOR_RED] = QEMU_PIXMAN_COLOR(0xff, 0x00, 0x00), /* red */
+ [QEMU_COLOR_MAGENTA] = QEMU_PIXMAN_COLOR(0xff, 0x00, 0xff), /* magenta */
+ [QEMU_COLOR_YELLOW] = QEMU_PIXMAN_COLOR(0xff, 0xff, 0x00), /* yellow */
+ [QEMU_COLOR_WHITE] = QEMU_PIXMAN_COLOR(0xff, 0xff, 0xff), /* white */
}
};
DisplaySurface *surface = qemu_console_surface(s);
pixman_color_t fgcol, bgcol;
+ assert(surface);
if (t_attrib->invers) {
bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
&fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
}
-static void text_console_resize(QemuConsole *s)
+static void text_console_resize(QemuTextConsole *t)
{
+ QemuConsole *s = QEMU_CONSOLE(t);
TextCell *cells, *c, *c1;
- int w1, x, y, last_width;
+ int w1, x, y, last_width, w, h;
assert(s->scanout.kind == SCANOUT_SURFACE);
- last_width = s->width;
- s->width = surface_width(s->surface) / FONT_WIDTH;
- s->height = surface_height(s->surface) / FONT_HEIGHT;
+ w = surface_width(s->surface) / FONT_WIDTH;
+ h = surface_height(s->surface) / FONT_HEIGHT;
+ if (w == t->width && h == t->height) {
+ return;
+ }
+
+ last_width = t->width;
+ t->width = w;
+ t->height = h;
- w1 = last_width;
- if (s->width < w1)
- w1 = s->width;
+ w1 = MIN(t->width, last_width);
- cells = g_new(TextCell, s->width * s->total_height + 1);
- for(y = 0; y < s->total_height; y++) {
- c = &cells[y * s->width];
+ cells = g_new(TextCell, t->width * t->total_height + 1);
+ for (y = 0; y < t->total_height; y++) {
+ c = &cells[y * t->width];
if (w1 > 0) {
- c1 = &s->cells[y * last_width];
- for(x = 0; x < w1; x++) {
+ c1 = &t->cells[y * last_width];
+ for (x = 0; x < w1; x++) {
*c++ = *c1++;
}
}
- for(x = w1; x < s->width; x++) {
+ for (x = w1; x < t->width; x++) {
c->ch = ' ';
c->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
c++;
}
}
- g_free(s->cells);
- s->cells = cells;
+ g_free(t->cells);
+ t->cells = cells;
}
-static void invalidate_xy(QemuConsole *s, int x, int y)
+static void invalidate_xy(QemuTextConsole *s, int x, int y)
{
- if (!qemu_console_is_visible(s)) {
+ if (!qemu_console_is_visible(QEMU_CONSOLE(s))) {
return;
}
if (s->update_x0 > x * FONT_WIDTH)
static void vc_update_xy(VCChardev *vc, int x, int y)
{
- QemuConsole *s = vc->console;
+ QemuTextConsole *s = vc->console;
TextCell *c;
int y1, y2;
x = s->width - 1;
}
c = &s->cells[y1 * s->width + x];
- vga_putcharxy(s, x, y2, c->ch,
+ vga_putcharxy(QEMU_CONSOLE(s), x, y2, c->ch,
&(c->t_attrib));
invalidate_xy(s, x, y2);
}
}
-static void console_show_cursor(QemuConsole *s, int show)
+static void console_show_cursor(QemuTextConsole *s, int show)
{
TextCell *c;
int y, y1;
if (show && cursor_visible_phase) {
TextAttributes t_attrib = TEXT_ATTRIBUTES_DEFAULT;
t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
- vga_putcharxy(s, x, y, c->ch, &t_attrib);
+ vga_putcharxy(QEMU_CONSOLE(s), x, y, c->ch, &t_attrib);
} else {
- vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
+ vga_putcharxy(QEMU_CONSOLE(s), x, y, c->ch, &(c->t_attrib));
}
invalidate_xy(s, x, y);
}
}
-static void console_refresh(QemuConsole *s)
+static void console_refresh(QemuTextConsole *s)
{
- DisplaySurface *surface = qemu_console_surface(s);
+ DisplaySurface *surface = qemu_console_surface(QEMU_CONSOLE(s));
TextCell *c;
int x, y, y1;
+ assert(surface);
s->text_x[0] = 0;
s->text_y[0] = 0;
s->text_x[1] = s->width - 1;
s->text_y[1] = s->height - 1;
s->cursor_invalidate = 1;
- vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
- color_table_rgb[0][QEMU_COLOR_BLACK]);
+ qemu_console_fill_rect(QEMU_CONSOLE(s), 0, 0, surface_width(surface), surface_height(surface),
+ color_table_rgb[0][QEMU_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, x, y, c->ch,
+ vga_putcharxy(QEMU_CONSOLE(s), x, y, c->ch,
&(c->t_attrib));
c++;
}
}
}
console_show_cursor(s, 1);
- dpy_gfx_update(s, 0, 0,
+ dpy_gfx_update(QEMU_CONSOLE(s), 0, 0,
surface_width(surface), surface_height(surface));
}
-static void console_scroll(QemuConsole *s, int ydelta)
+static void console_scroll(QemuTextConsole *s, int ydelta)
{
int i, y1;
static void vc_put_lf(VCChardev *vc)
{
- QemuConsole *s = vc->console;
+ QemuTextConsole *s = vc->console;
TextCell *c;
int x, y1;
s->text_x[1] = s->width - 1;
s->text_y[1] = s->height - 1;
- 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][TEXT_ATTRIBUTES_DEFAULT.bgcol]);
+ qemu_console_bitblt(QEMU_CONSOLE(s), 0, FONT_HEIGHT, 0, 0,
+ s->width * FONT_WIDTH,
+ (s->height - 1) * FONT_HEIGHT);
+ qemu_console_fill_rect(QEMU_CONSOLE(s), 0, (s->height - 1) * FONT_HEIGHT,
+ s->width * FONT_WIDTH, FONT_HEIGHT,
+ color_table_rgb[0][TEXT_ATTRIBUTES_DEFAULT.bgcol]);
s->update_x0 = 0;
s->update_y0 = 0;
s->update_x1 = s->width * FONT_WIDTH;
static void vc_clear_xy(VCChardev *vc, int x, int y)
{
- QemuConsole *s = vc->console;
+ QemuTextConsole *s = vc->console;
int y1 = (s->y_base + y) % s->total_height;
if (x >= s->width) {
x = s->width - 1;
static void vc_put_one(VCChardev *vc, int ch)
{
- QemuConsole *s = vc->console;
+ QemuTextConsole *s = vc->console;
TextCell *c;
int y1;
if (s->x >= s->width) {
/* set cursor, checking bounds */
static void vc_set_cursor(VCChardev *vc, int x, int y)
{
- QemuConsole *s = vc->console;
+ QemuTextConsole *s = vc->console;
if (x < 0) {
x = 0;
static void vc_putchar(VCChardev *vc, int ch)
{
- QemuConsole *s = vc->console;
+ QemuTextConsole *s = vc->console;
int i;
int x, y;
char response[40];
}
}
+static void
+qemu_text_console_select(QemuTextConsole *c)
+{
+ dpy_text_resize(QEMU_CONSOLE(c), c->width, c->height);
+ qemu_text_console_update_cursor(NULL);
+}
+
void console_select(unsigned int index)
{
DisplayChangeListener *dcl;
}
displaychangelistener_display_console(dcl, s, NULL);
}
- dpy_text_resize(s, s->width, s->height);
- text_console_update_cursor(NULL);
+
+ if (QEMU_IS_TEXT_CONSOLE(s)) {
+ qemu_text_console_select(QEMU_TEXT_CONSOLE(s));
+ }
}
}
static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
{
VCChardev *drv = VC_CHARDEV(chr);
- QemuConsole *s = drv->console;
+ QemuTextConsole *s = drv->console;
int i;
s->update_x0 = s->width * FONT_WIDTH;
}
console_show_cursor(s, 1);
if (s->update_x0 < s->update_x1) {
- dpy_gfx_update(s, s->update_x0, s->update_y0,
+ dpy_gfx_update(QEMU_CONSOLE(s), s->update_x0, s->update_y0,
s->update_x1 - s->update_x0,
s->update_y1 - s->update_y0);
}
return len;
}
-static void kbd_send_chars(QemuConsole *s)
+static void kbd_send_chars(QemuTextConsole *s)
{
uint32_t len, avail;
}
/* called when an ascii key is pressed */
-void kbd_put_keysym_console(QemuConsole *s, int keysym)
+static void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym)
{
uint8_t buf[16], *q;
int c;
uint32_t num_free;
- if (!s || (s->console_type == GRAPHIC_CONSOLE))
- return;
-
switch(keysym) {
case QEMU_KEY_CTRL_UP:
console_scroll(s, -1);
}
}
+void qemu_text_console_put_keysym(QemuTextConsole *s, int keysym)
+{
+ if (!s) {
+ if (!QEMU_IS_TEXT_CONSOLE(active_console)) {
+ return;
+ }
+ s = QEMU_TEXT_CONSOLE(active_console);
+ }
+
+ qemu_text_console_handle_keysym(s, keysym);
+}
+
static const int qcode_to_keysym[Q_KEY_CODE__MAX] = {
[Q_KEY_CODE_UP] = QEMU_KEY_UP,
[Q_KEY_CODE_DOWN] = QEMU_KEY_DOWN,
[Q_KEY_CODE_PGDN] = QEMU_KEY_CTRL_PAGEDOWN,
};
-bool kbd_put_qcode_console(QemuConsole *s, int qcode, bool ctrl)
+bool qemu_text_console_put_qcode(QemuTextConsole *s, int qcode, bool ctrl)
{
int keysym;
if (keysym == 0) {
return false;
}
- kbd_put_keysym_console(s, keysym);
+ qemu_text_console_put_keysym(s, keysym);
return true;
}
-void kbd_put_string_console(QemuConsole *s, const char *str, int len)
+void qemu_text_console_put_string(QemuTextConsole *s, const char *str, int len)
{
int i;
for (i = 0; i < len && str[i]; i++) {
- kbd_put_keysym_console(s, str[i]);
+ qemu_text_console_put_keysym(s, str[i]);
}
}
-void kbd_put_keysym(int keysym)
-{
- kbd_put_keysym_console(active_console, keysym);
-}
-
static void text_console_invalidate(void *opaque)
{
- QemuConsole *s = (QemuConsole *) opaque;
+ QemuTextConsole *s = QEMU_TEXT_CONSOLE(opaque);
- if (s->console_type == TEXT_CONSOLE) {
- text_console_resize(s);
+ if (!QEMU_IS_FIXED_TEXT_CONSOLE(s)) {
+ text_console_resize(QEMU_TEXT_CONSOLE(s));
}
console_refresh(s);
}
static void text_console_update(void *opaque, console_ch_t *chardata)
{
- QemuConsole *s = (QemuConsole *) opaque;
+ QemuTextConsole *s = QEMU_TEXT_CONSOLE(opaque);
int i, j, src;
if (s->text_x[0] <= s->text_x[1]) {
s->cells[src].t_attrib.bgcol,
s->cells[src].t_attrib.bold));
}
- dpy_text_update(s, s->text_x[0], s->text_y[0],
+ dpy_text_update(QEMU_CONSOLE(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, s->x, s->y);
+ dpy_text_cursor(QEMU_CONSOLE(s), s->x, s->y);
s->cursor_invalidate = 0;
}
}
-static QemuConsole *new_console(console_type_t console_type, uint32_t head)
+static void
+qemu_console_register(QemuConsole *c)
{
- DisplayState *ds = get_alloc_displaystate();
- Object *obj;
- QemuConsole *s;
int i;
- obj = object_new(TYPE_QEMU_CONSOLE);
- s = QEMU_CONSOLE(obj);
- qemu_co_queue_init(&s->dump_queue);
- s->head = head;
- object_property_add_link(obj, "device", TYPE_DEVICE,
- (Object **)&s->device,
- object_property_allow_set_link,
- OBJ_PROP_LINK_STRONG);
- object_property_add_uint32_ptr(obj, "head", &s->head,
- OBJ_PROP_FLAG_READ);
-
- if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
- (console_type == GRAPHIC_CONSOLE))) {
- active_console = s;
+ if (!active_console || (!QEMU_IS_GRAPHIC_CONSOLE(active_console) &&
+ QEMU_IS_GRAPHIC_CONSOLE(c))) {
+ active_console = c;
}
- s->ds = ds;
- s->console_type = console_type;
- s->window_id = -1;
if (QTAILQ_EMPTY(&consoles)) {
- s->index = 0;
- QTAILQ_INSERT_TAIL(&consoles, s, next);
- } else if (console_type != GRAPHIC_CONSOLE || phase_check(PHASE_MACHINE_READY)) {
+ c->index = 0;
+ QTAILQ_INSERT_TAIL(&consoles, c, next);
+ } else if (!QEMU_IS_GRAPHIC_CONSOLE(c) || phase_check(PHASE_MACHINE_READY)) {
QemuConsole *last = QTAILQ_LAST(&consoles);
- s->index = last->index + 1;
- QTAILQ_INSERT_TAIL(&consoles, s, next);
+ c->index = last->index + 1;
+ QTAILQ_INSERT_TAIL(&consoles, c, next);
} else {
/*
* HACK: Put graphical consoles before text consoles.
* Only do that for coldplugged devices. After initial device
* initialization we will not renumber the consoles any more.
*/
- QemuConsole *c = QTAILQ_FIRST(&consoles);
+ QemuConsole *it = QTAILQ_FIRST(&consoles);
- while (QTAILQ_NEXT(c, next) != NULL &&
- c->console_type == GRAPHIC_CONSOLE) {
- c = QTAILQ_NEXT(c, next);
+ while (QTAILQ_NEXT(it, next) != NULL && QEMU_IS_GRAPHIC_CONSOLE(it)) {
+ it = QTAILQ_NEXT(it, next);
}
- if (c->console_type == GRAPHIC_CONSOLE) {
+ if (QEMU_IS_GRAPHIC_CONSOLE(it)) {
/* have no text consoles */
- s->index = c->index + 1;
- QTAILQ_INSERT_AFTER(&consoles, c, s, next);
+ c->index = it->index + 1;
+ QTAILQ_INSERT_AFTER(&consoles, it, c, next);
} else {
- s->index = c->index;
- QTAILQ_INSERT_BEFORE(c, s, next);
+ c->index = it->index;
+ QTAILQ_INSERT_BEFORE(it, c, next);
/* renumber text consoles */
- for (i = s->index + 1; c != NULL; c = QTAILQ_NEXT(c, next), i++) {
- c->index = i;
+ for (i = c->index + 1; it != NULL; it = QTAILQ_NEXT(it, next), i++) {
+ it->index = i;
}
}
}
- return s;
+}
+
+static void
+qemu_console_finalize(Object *obj)
+{
+ QemuConsole *c = QEMU_CONSOLE(obj);
+
+ /* TODO: check this code path, and unregister from consoles */
+ g_clear_pointer(&c->surface, qemu_free_displaysurface);
+ g_clear_pointer(&c->gl_unblock_timer, timer_free);
+ g_clear_pointer(&c->ui_timer, timer_free);
+}
+
+static void
+qemu_console_class_init(ObjectClass *oc, void *data)
+{
+}
+
+static void
+qemu_console_init(Object *obj)
+{
+ QemuConsole *c = QEMU_CONSOLE(obj);
+ DisplayState *ds = get_alloc_displaystate();
+
+ qemu_co_queue_init(&c->dump_queue);
+ c->ds = ds;
+ c->window_id = -1;
+ c->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
+ dpy_set_ui_info_timer, c);
+ qemu_console_register(c);
+}
+
+static void
+qemu_graphic_console_finalize(Object *obj)
+{
+ QemuGraphicConsole *c = QEMU_GRAPHIC_CONSOLE(obj);
+
+ g_clear_pointer(&c->device, object_unref);
+}
+
+static void
+qemu_graphic_console_prop_get_head(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ QemuGraphicConsole *c = QEMU_GRAPHIC_CONSOLE(obj);
+
+ visit_type_uint32(v, name, &c->head, errp);
+}
+
+static void
+qemu_graphic_console_class_init(ObjectClass *oc, void *data)
+{
+ object_class_property_add_link(oc, "device", TYPE_DEVICE,
+ offsetof(QemuGraphicConsole, device),
+ object_property_allow_set_link,
+ OBJ_PROP_LINK_STRONG);
+ object_class_property_add(oc, "head", "uint32",
+ qemu_graphic_console_prop_get_head,
+ NULL, NULL, NULL);
+}
+
+static void
+qemu_graphic_console_init(Object *obj)
+{
+}
+
+static void
+qemu_text_console_finalize(Object *obj)
+{
+}
+
+static void
+qemu_text_console_class_init(ObjectClass *oc, void *data)
+{
+ if (!cursor_timer) {
+ cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
+ qemu_text_console_update_cursor, NULL);
+ }
+}
+
+static const GraphicHwOps text_console_ops = {
+ .invalidate = text_console_invalidate,
+ .text_update = text_console_update,
+};
+
+static void
+qemu_text_console_init(Object *obj)
+{
+ QemuTextConsole *c = QEMU_TEXT_CONSOLE(obj);
+
+ fifo8_create(&c->out_fifo, 16);
+ c->total_height = DEFAULT_BACKSCROLL;
+ QEMU_CONSOLE(c)->hw_ops = &text_console_ops;
+ QEMU_CONSOLE(c)->hw = c;
+}
+
+static void
+qemu_fixed_text_console_finalize(Object *obj)
+{
+}
+
+static void
+qemu_fixed_text_console_class_init(ObjectClass *oc, void *data)
+{
+}
+
+static void
+qemu_fixed_text_console_init(Object *obj)
+{
}
#ifdef WIN32
DisplaySurface *surface = g_new0(DisplaySurface, 1);
trace_displaysurface_create_from(surface, width, height, format);
- surface->format = format;
- surface->image = pixman_image_create_bits(surface->format,
+ surface->image = pixman_image_create_bits(format,
width, height,
(void *)data, linesize);
assert(surface->image != NULL);
DisplaySurface *surface = g_new0(DisplaySurface, 1);
trace_displaysurface_create_pixman(surface);
- surface->format = pixman_image_get_format(image);
surface->image = pixman_image_ref(image);
return surface;
const char *msg)
{
DisplaySurface *surface = qemu_create_displaysurface(w, h);
- pixman_color_t bg = color_table_rgb[0][QEMU_COLOR_BLACK];
- pixman_color_t fg = color_table_rgb[0][QEMU_COLOR_WHITE];
+ pixman_color_t bg = QEMU_PIXMAN_COLOR_BLACK;
+ pixman_color_t fg = QEMU_PIXMAN_COLOR_GRAY;
pixman_image_t *glyph;
int len, x, y, i;
con->gl = gl;
}
+static void
+dcl_set_graphic_cursor(DisplayChangeListener *dcl, QemuGraphicConsole *con)
+{
+ if (con && con->cursor && dcl->ops->dpy_cursor_define) {
+ dcl->ops->dpy_cursor_define(dcl, con->cursor);
+ }
+ if (con && dcl->ops->dpy_mouse_set) {
+ dcl->ops->dpy_mouse_set(dcl, con->cursor_x, con->cursor_y, con->cursor_on);
+ }
+}
void register_displaychangelistener(DisplayChangeListener *dcl)
{
QemuConsole *con;
con = active_console;
}
displaychangelistener_display_console(dcl, con, dcl->con ? &error_fatal : NULL);
- if (con && con->cursor && dcl->ops->dpy_cursor_define) {
- dcl->ops->dpy_cursor_define(dcl, con->cursor);
+ if (QEMU_IS_GRAPHIC_CONSOLE(con)) {
+ dcl_set_graphic_cursor(dcl, QEMU_GRAPHIC_CONSOLE(con));
}
- if (con && dcl->ops->dpy_mouse_set) {
- dcl->ops->dpy_mouse_set(dcl, con->cursor_x, con->cursor_y, con->cursor_on);
- }
- text_console_update_cursor(NULL);
+ qemu_text_console_update_cursor(NULL);
}
void update_displaychangelistener(DisplayChangeListener *dcl,
static void dpy_set_ui_info_timer(void *opaque)
{
QemuConsole *con = opaque;
+ uint32_t head = qemu_console_get_head(con);
- con->hw_ops->ui_info(con->hw, con->head, &con->ui_info);
+ con->hw_ops->ui_info(con->hw, head, &con->ui_info);
}
bool dpy_ui_info_supported(QemuConsole *con)
}
}
-void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
+void dpy_mouse_set(QemuConsole *c, int x, int y, int on)
{
- DisplayState *s = con->ds;
+ QemuGraphicConsole *con = QEMU_GRAPHIC_CONSOLE(c);
+ DisplayState *s = c->ds;
DisplayChangeListener *dcl;
con->cursor_x = x;
con->cursor_y = y;
con->cursor_on = on;
- if (!qemu_console_is_visible(con)) {
+ if (!qemu_console_is_visible(c)) {
return;
}
QLIST_FOREACH(dcl, &s->listeners, next) {
- if (con != (dcl->con ? dcl->con : active_console)) {
+ if (c != (dcl->con ? dcl->con : active_console)) {
continue;
}
if (dcl->ops->dpy_mouse_set) {
}
}
-void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
+void dpy_cursor_define(QemuConsole *c, QEMUCursor *cursor)
{
- DisplayState *s = con->ds;
+ QemuGraphicConsole *con = QEMU_GRAPHIC_CONSOLE(c);
+ DisplayState *s = c->ds;
DisplayChangeListener *dcl;
cursor_unref(con->cursor);
con->cursor = cursor_ref(cursor);
- if (!qemu_console_is_visible(con)) {
+ if (!qemu_console_is_visible(c)) {
return;
}
QLIST_FOREACH(dcl, &s->listeners, next) {
- if (con != (dcl->con ? dcl->con : active_console)) {
+ if (c != (dcl->con ? dcl->con : active_console)) {
continue;
}
if (dcl->ops->dpy_cursor_define) {
{
if (!display_state) {
display_state = g_new0(DisplayState, 1);
- cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
- text_console_update_cursor, NULL);
}
return display_state;
}
QemuConsole *con;
QTAILQ_FOREACH(con, &consoles, next) {
- /* Hook up into the qom tree here (not in new_console()), once
+ /* Hook up into the qom tree here (not in object_new()), once
* all QemuConsoles are created and the order / numbering
* doesn't change any more */
name = g_strdup_printf("console[%d]", con->index);
QemuConsole *s;
DisplaySurface *surface;
- s = qemu_console_lookup_unused();
+ s = qemu_graphic_console_lookup_unused();
if (s) {
trace_console_gfx_reuse(s->index);
width = qemu_console_get_width(s, 0);
height = qemu_console_get_height(s, 0);
} else {
trace_console_gfx_new();
- s = new_console(GRAPHIC_CONSOLE, head);
- s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
- dpy_set_ui_info_timer, s);
+ s = (QemuConsole *)object_new(TYPE_QEMU_GRAPHIC_CONSOLE);
}
+ QEMU_GRAPHIC_CONSOLE(s)->head = head;
graphic_console_set_hwops(s, hw_ops, opaque);
if (dev) {
object_property_set_link(OBJECT(s), "device", OBJECT(dev),
return con;
}
-QemuConsole *qemu_console_lookup_unused(void)
+static QemuConsole *qemu_graphic_console_lookup_unused(void)
{
QemuConsole *con;
Object *obj;
QTAILQ_FOREACH(con, &consoles, next) {
- if (con->hw_ops != &unused_ops) {
+ if (!QEMU_IS_GRAPHIC_CONSOLE(con) || con->hw_ops != &unused_ops) {
continue;
}
obj = object_property_get_link(OBJECT(con),
if (con == NULL) {
con = active_console;
}
- return con ? con->cursor : NULL;
+ return QEMU_IS_GRAPHIC_CONSOLE(con) ? QEMU_GRAPHIC_CONSOLE(con)->cursor : NULL;
}
bool qemu_console_is_visible(QemuConsole *con)
if (con == NULL) {
con = active_console;
}
- return con && (con->console_type == GRAPHIC_CONSOLE);
+ return con && QEMU_IS_GRAPHIC_CONSOLE(con);
}
bool qemu_console_is_fixedsize(QemuConsole *con)
if (con == NULL) {
con = active_console;
}
- return con && (con->console_type != TEXT_CONSOLE);
+ return con && (QEMU_IS_GRAPHIC_CONSOLE(con) || QEMU_IS_FIXED_TEXT_CONSOLE(con));
}
bool qemu_console_is_gl_blocked(QemuConsole *con)
return false;
}
+
+static const char *
+qemu_text_console_get_label(QemuTextConsole *c)
+{
+ return c->chr ? c->chr->label : NULL;
+}
+
char *qemu_console_get_label(QemuConsole *con)
{
- if (con->console_type == GRAPHIC_CONSOLE) {
- if (con->device) {
+ if (QEMU_IS_GRAPHIC_CONSOLE(con)) {
+ QemuGraphicConsole *c = QEMU_GRAPHIC_CONSOLE(con);
+ if (c->device) {
DeviceState *dev;
bool multihead;
- dev = DEVICE(con->device);
+ dev = DEVICE(c->device);
multihead = qemu_console_is_multihead(dev);
if (multihead) {
return g_strdup_printf("%s.%d", dev->id ?
dev->id :
- object_get_typename(con->device),
- con->head);
+ object_get_typename(c->device),
+ c->head);
} else {
return g_strdup_printf("%s", dev->id ?
dev->id :
- object_get_typename(con->device));
+ object_get_typename(c->device));
}
}
return g_strdup("VGA");
- } else {
- if (con->chr && con->chr->label) {
- return g_strdup(con->chr->label);
+ } else if (QEMU_IS_TEXT_CONSOLE(con)) {
+ const char *label = qemu_text_console_get_label(QEMU_TEXT_CONSOLE(con));
+ if (label) {
+ return g_strdup(label);
}
- return g_strdup_printf("vc%d", con->index);
}
+
+ return g_strdup_printf("vc%d", con->index);
}
int qemu_console_get_index(QemuConsole *con)
if (con == NULL) {
con = active_console;
}
- return con ? con->head : -1;
+ if (con == NULL) {
+ return -1;
+ }
+ if (QEMU_IS_GRAPHIC_CONSOLE(con)) {
+ return QEMU_GRAPHIC_CONSOLE(con)->head;
+ }
+ return 0;
}
int qemu_console_get_width(QemuConsole *con, int fallback)
static void vc_chr_accept_input(Chardev *chr)
{
VCChardev *drv = VC_CHARDEV(chr);
- QemuConsole *s = drv->console;
- kbd_send_chars(s);
+ kbd_send_chars(drv->console);
}
static void vc_chr_set_echo(Chardev *chr, bool echo)
{
VCChardev *drv = VC_CHARDEV(chr);
- QemuConsole *s = drv->console;
-
- s->echo = echo;
-}
-static void text_console_update_cursor_timer(void)
-{
- timer_mod(cursor_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
- + CONSOLE_CURSOR_PERIOD / 2);
+ drv->console->echo = echo;
}
-static void text_console_update_cursor(void *opaque)
+int qemu_invalidate_text_consoles(void)
{
QemuConsole *s;
int count = 0;
- cursor_visible_phase = !cursor_visible_phase;
-
QTAILQ_FOREACH(s, &consoles, next) {
if (qemu_console_is_graphic(s) ||
!qemu_console_is_visible(s)) {
graphic_hw_invalidate(s);
}
- if (count) {
- text_console_update_cursor_timer();
- }
+ return count;
}
-static const GraphicHwOps text_console_ops = {
- .invalidate = text_console_invalidate,
- .text_update = text_console_update,
-};
-
-static void text_console_do_init(Chardev *chr)
+static void qemu_text_console_update_cursor(void *opaque)
{
- VCChardev *drv = VC_CHARDEV(chr);
- QemuConsole *s = drv->console;
- int g_width = 80 * FONT_WIDTH;
- int g_height = 24 * FONT_HEIGHT;
-
- fifo8_create(&s->out_fifo, 16);
+ cursor_visible_phase = !cursor_visible_phase;
- s->y_displayed = 0;
- s->y_base = 0;
- s->total_height = DEFAULT_BACKSCROLL;
- s->x = 0;
- s->y = 0;
- if (s->scanout.kind != SCANOUT_SURFACE) {
- if (active_console && active_console->scanout.kind == SCANOUT_SURFACE) {
- g_width = qemu_console_get_width(active_console, g_width);
- g_height = qemu_console_get_height(active_console, g_height);
- }
- s->surface = qemu_create_displaysurface(g_width, g_height);
- s->scanout.kind = SCANOUT_SURFACE;
+ if (qemu_invalidate_text_consoles()) {
+ timer_mod(cursor_timer,
+ qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2);
}
-
- s->hw_ops = &text_console_ops;
- s->hw = s;
-
- /* set current text attributes to default */
- drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
- text_console_resize(s);
-
- if (chr->label) {
- char *msg;
-
- drv->t_attrib.bgcol = QEMU_COLOR_BLUE;
- msg = g_strdup_printf("%s console\r\n", chr->label);
- qemu_chr_write(chr, (uint8_t *)msg, strlen(msg), true);
- g_free(msg);
- drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
- }
-
- qemu_chr_be_event(chr, CHR_EVENT_OPENED);
}
static void vc_chr_open(Chardev *chr,
{
ChardevVC *vc = backend->u.vc.data;
VCChardev *drv = VC_CHARDEV(chr);
- QemuConsole *s;
+ QemuTextConsole *s;
unsigned width = 0;
unsigned height = 0;
trace_console_txt_new(width, height);
if (width == 0 || height == 0) {
- s = new_console(TEXT_CONSOLE, 0);
+ s = QEMU_TEXT_CONSOLE(object_new(TYPE_QEMU_TEXT_CONSOLE));
+ width = qemu_console_get_width(NULL, 80 * FONT_WIDTH);
+ height = qemu_console_get_height(NULL, 24 * FONT_HEIGHT);
} else {
- s = new_console(TEXT_CONSOLE_FIXED_SIZE, 0);
- s->scanout.kind = SCANOUT_SURFACE;
- s->surface = qemu_create_displaysurface(width, height);
+ s = QEMU_TEXT_CONSOLE(object_new(TYPE_QEMU_FIXED_TEXT_CONSOLE));
}
+ dpy_gfx_replace_surface(QEMU_CONSOLE(s), qemu_create_displaysurface(width, height));
+
s->chr = chr;
drv->console = s;
- text_console_do_init(chr);
+ /* set current text attributes to default */
+ drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
+ text_console_resize(s);
- /* console/chardev init sometimes completes elsewhere in a 2nd
- * stage, so defer OPENED events until they are fully initialized
- */
- *be_opened = false;
+ if (chr->label) {
+ char *msg;
+
+ drv->t_attrib.bgcol = QEMU_COLOR_BLUE;
+ msg = g_strdup_printf("%s console\r\n", chr->label);
+ qemu_chr_write(chr, (uint8_t *)msg, strlen(msg), true);
+ g_free(msg);
+ drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
+ }
+
+ *be_opened = true;
}
void qemu_console_resize(QemuConsole *s, int width, int height)
{
DisplaySurface *surface = qemu_console_surface(s);
- assert(s->console_type == GRAPHIC_CONSOLE);
+ assert(QEMU_IS_GRAPHIC_CONSOLE(s));
if ((s->scanout.kind != SCANOUT_SURFACE ||
(surface && surface->flags & QEMU_ALLOCATED_FLAG)) &&
}
}
-void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, Error **errp)
+static void vc_chr_parse(QemuOpts *opts, ChardevBackend *backend, Error **errp)
{
int val;
ChardevVC *vc;
}
}
-static const TypeInfo qemu_console_info = {
- .name = TYPE_QEMU_CONSOLE,
- .parent = TYPE_OBJECT,
- .instance_size = sizeof(QemuConsole),
- .class_size = sizeof(QemuConsoleClass),
-};
-
static void char_vc_class_init(ObjectClass *oc, void *data)
{
ChardevClass *cc = CHARDEV_CLASS(oc);
- cc->parse = qemu_chr_parse_vc;
+ cc->parse = vc_chr_parse;
cc->open = vc_chr_open;
cc->chr_write = vc_chr_write;
cc->chr_accept_input = vc_chr_accept_input;
type_register(&char_vc_type_info);
}
}
-
-static void register_types(void)
-{
- type_register_static(&qemu_console_info);
-}
-
-type_init(register_types);