X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/439229c7cb97f6c4cddd3965c3e9d2b8319fe83c..5a17077529f7feec559e1881792e89554c2ae5b6:/console.c diff --git a/console.c b/console.c index f6fe44195b..3f3d2547bf 100644 --- a/console.c +++ b/console.c @@ -24,10 +24,12 @@ #include "qemu-common.h" #include "console.h" #include "qemu-timer.h" +#include "qmp-commands.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) @@ -139,6 +141,8 @@ struct TextConsole { TextCell *cells; int text_x[2], text_y[2], cursor_invalidate; int echo; + bool cursor_visible_phase; + QEMUTimer *cursor_timer; int update_x0; int update_y0; @@ -173,20 +177,28 @@ void vga_hw_invalidate(void) active_console->hw_invalidate(active_console->hw); } -void vga_hw_screen_dump(const char *filename) +void qmp_screendump(const char *filename, Error **errp) { TextConsole *previous_active_console; + bool cswitch; previous_active_console = active_console; + cswitch = previous_active_console && previous_active_console->index != 0; /* There is currently no way of specifying which screen we want to dump, so always dump the first one. */ - console_select(0); + if (cswitch) { + console_select(0); + } if (consoles[0] && consoles[0]->hw_screen_dump) { - consoles[0]->hw_screen_dump(consoles[0]->hw, filename); + consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch, errp); + } else { + error_setg(errp, "device doesn't support screendump\n"); } - console_select(previous_active_console->index); + if (cswitch) { + console_select(previous_active_console->index); + } } void vga_hw_text_update(console_ch_t *chardata) @@ -607,7 +619,7 @@ static void console_show_cursor(TextConsole *s, int show) y += s->total_height; if (y < s->height) { c = &s->cells[y1 * s->width + x]; - if (show) { + if (show && s->cursor_visible_phase) { TextAttributes t_attrib = s->t_attrib_default; t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */ vga_putcharxy(s->ds, x, y, c->ch, &t_attrib); @@ -839,6 +851,26 @@ static void console_clear_xy(TextConsole *s, int x, int y) update_xy(s, x, y); } +/* set cursor, checking bounds */ +static void set_cursor(TextConsole *s, int x, int y) +{ + if (x < 0) { + x = 0; + } + if (y < 0) { + y = 0; + } + if (y >= s->height) { + y = s->height - 1; + } + if (x >= s->width) { + x = s->width - 1; + } + + s->x = x; + s->y = y; +} + static void console_putchar(TextConsole *s, int ch) { TextCell *c; @@ -906,11 +938,15 @@ static void console_putchar(TextConsole *s, int ch) case TTY_STATE_CSI: /* handle escape sequence parameters */ if (ch >= '0' && ch <= '9') { if (s->nb_esc_params < MAX_ESC_PARAMS) { - s->esc_params[s->nb_esc_params] = - s->esc_params[s->nb_esc_params] * 10 + ch - '0'; + int *param = &s->esc_params[s->nb_esc_params]; + int digit = (ch - '0'); + + *param = (*param <= (INT_MAX - digit) / 10) ? + *param * 10 + digit : INT_MAX; } } else { - s->nb_esc_params++; + if (s->nb_esc_params < MAX_ESC_PARAMS) + s->nb_esc_params++; if (ch == ';') break; #ifdef DEBUG_CONSOLE @@ -924,59 +960,37 @@ static void console_putchar(TextConsole *s, int ch) if (s->esc_params[0] == 0) { s->esc_params[0] = 1; } - s->y -= s->esc_params[0]; - if (s->y < 0) { - s->y = 0; - } + set_cursor(s, s->x, s->y - s->esc_params[0]); break; case 'B': /* move cursor down */ if (s->esc_params[0] == 0) { s->esc_params[0] = 1; } - s->y += s->esc_params[0]; - if (s->y >= s->height) { - s->y = s->height - 1; - } + set_cursor(s, s->x, s->y + s->esc_params[0]); break; case 'C': /* move cursor right */ if (s->esc_params[0] == 0) { s->esc_params[0] = 1; } - s->x += s->esc_params[0]; - if (s->x >= s->width) { - s->x = s->width - 1; - } + set_cursor(s, s->x + s->esc_params[0], s->y); break; case 'D': /* move cursor left */ if (s->esc_params[0] == 0) { s->esc_params[0] = 1; } - s->x -= s->esc_params[0]; - if (s->x < 0) { - s->x = 0; - } + set_cursor(s, s->x - s->esc_params[0], s->y); break; case 'G': /* move cursor to column */ - s->x = s->esc_params[0] - 1; - if (s->x < 0) { - s->x = 0; - } + set_cursor(s, s->esc_params[0] - 1, s->y); break; case 'f': case 'H': /* move cursor to row, column */ - s->x = s->esc_params[1] - 1; - if (s->x < 0) { - s->x = 0; - } - s->y = s->esc_params[0] - 1; - if (s->y < 0) { - s->y = 0; - } + set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1); break; case 'J': switch (s->esc_params[0]) { @@ -1009,16 +1023,17 @@ static void console_putchar(TextConsole *s, int ch) console_clear_xy(s, x, y); } } - break; + break; } + break; case 'K': switch (s->esc_params[0]) { case 0: - /* clear to eol */ - for(x = s->x; x < s->width; x++) { + /* clear to eol */ + for(x = s->x; x < s->width; x++) { console_clear_xy(s, x, s->y); - } - break; + } + break; case 1: /* clear from beginning of line */ for (x = 0; x <= s->x; x++) { @@ -1030,12 +1045,12 @@ static void console_putchar(TextConsole *s, int ch) for(x = 0; x < s->width; x++) { console_clear_xy(s, x, s->y); } - break; - } + break; + } break; case 'm': - console_handle_escape(s); - break; + console_handle_escape(s); + break; case 'n': /* report cursor position */ /* TODO: send ESC[row;colR */ @@ -1074,6 +1089,10 @@ void console_select(unsigned int index) s = consoles[index]; if (s) { DisplayState *ds = s->ds; + + if (active_console && active_console->cursor_timer) { + qemu_del_timer(active_console->cursor_timer); + } active_console = s; if (ds_get_bits_per_pixel(s->ds)) { ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height); @@ -1081,6 +1100,10 @@ void console_select(unsigned int index) s->ds->surface->width = s->width; s->ds->surface->height = s->height; } + if (s->cursor_timer) { + qemu_mod_timer(s->cursor_timer, + qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2); + } dpy_resize(s->ds); vga_hw_invalidate(); } @@ -1438,9 +1461,6 @@ void console_color_init(DisplayState *ds) } } -static int n_text_consoles; -static CharDriverState *text_consoles[128]; - static void text_console_set_echo(CharDriverState *chr, bool echo) { TextConsole *s = chr->opaque; @@ -1448,6 +1468,16 @@ static void text_console_set_echo(CharDriverState *chr, bool echo) s->echo = echo; } +static void text_console_update_cursor(void *opaque) +{ + TextConsole *s = opaque; + + s->cursor_visible_phase = !s->cursor_visible_phase; + vga_hw_invalidate(); + qemu_mod_timer(s->cursor_timer, + qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2); +} + static void text_console_do_init(CharDriverState *chr, DisplayState *ds) { TextConsole *s; @@ -1476,6 +1506,9 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds) s->g_height = ds_get_height(s->ds); } + 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 = s; @@ -1507,7 +1540,7 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds) chr->init(chr); } -int text_console_init(QemuOpts *opts, CharDriverState **_chr) +CharDriverState *text_console_init(QemuOpts *opts) { CharDriverState *chr; TextConsole *s; @@ -1516,13 +1549,6 @@ int text_console_init(QemuOpts *opts, CharDriverState **_chr) chr = g_malloc0(sizeof(CharDriverState)); - if (n_text_consoles == 128) { - fprintf(stderr, "Too many text consoles\n"); - exit(1); - } - text_consoles[n_text_consoles] = chr; - n_text_consoles++; - width = qemu_opt_get_number(opts, "width", 0); if (width == 0) width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH; @@ -1539,7 +1565,7 @@ int text_console_init(QemuOpts *opts, CharDriverState **_chr) if (!s) { g_free(chr); - return -EBUSY; + return NULL; } s->chr = chr; @@ -1547,20 +1573,18 @@ int text_console_init(QemuOpts *opts, CharDriverState **_chr) s->g_height = height; chr->opaque = s; chr->chr_set_echo = text_console_set_echo; - - *_chr = chr; - return 0; + return chr; } void text_consoles_set_display(DisplayState *ds) { int i; - for (i = 0; i < n_text_consoles; i++) { - text_console_do_init(text_consoles[i], ds); + for (i = 0; i < nb_consoles; i++) { + if (consoles[i]->console_type != GRAPHIC_CONSOLE) { + text_console_do_init(consoles[i]->chr, ds); + } } - - n_text_consoles = 0; } void qemu_console_resize(DisplayState *ds, int width, int height) @@ -1591,7 +1615,7 @@ PixelFormat qemu_different_endianness_pixelformat(int bpp) memset(&pf, 0x00, sizeof(PixelFormat)); pf.bits_per_pixel = bpp; - pf.bytes_per_pixel = bpp / 8; + pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8); pf.depth = bpp == 32 ? 24 : bpp; switch (bpp) { @@ -1640,13 +1664,12 @@ PixelFormat qemu_default_pixelformat(int bpp) memset(&pf, 0x00, sizeof(PixelFormat)); pf.bits_per_pixel = bpp; - pf.bytes_per_pixel = bpp / 8; + pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8); pf.depth = bpp == 32 ? 24 : bpp; switch (bpp) { case 15: pf.bits_per_pixel = 16; - pf.bytes_per_pixel = 2; pf.rmask = 0x00007c00; pf.gmask = 0x000003E0; pf.bmask = 0x0000001F; @@ -1687,6 +1710,7 @@ PixelFormat qemu_default_pixelformat(int bpp) pf.rbits = 8; pf.gbits = 8; pf.bbits = 8; + break; case 32: pf.rmask = 0x00FF0000; pf.gmask = 0x0000FF00;