From 90da7d552fbcb19d1fbf68b2051f0f168b8a48f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:35 +0400 Subject: ui: remove qemu_pixman_color() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Usage removed in commit e27bd65a72d ("console: switch color_table_rgb to pixman_color_t") Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230830093843.3531473-2-marcandre.lureau@redhat.com> --- ui/qemu-pixman.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'ui') diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c index e4f024a..c5053cd 100644 --- a/ui/qemu-pixman.c +++ b/ui/qemu-pixman.c @@ -226,17 +226,6 @@ void qemu_pixman_image_unref(pixman_image_t *image) pixman_image_unref(image); } -pixman_color_t qemu_pixman_color(PixelFormat *pf, uint32_t color) -{ - pixman_color_t c; - - c.red = ((color & pf->rmask) >> pf->rshift) << (16 - pf->rbits); - c.green = ((color & pf->gmask) >> pf->gshift) << (16 - pf->gbits); - c.blue = ((color & pf->bmask) >> pf->bshift) << (16 - pf->bbits); - c.alpha = ((color & pf->amask) >> pf->ashift) << (16 - pf->abits); - return c; -} - pixman_image_t *qemu_pixman_glyph_from_vgafont(int height, const uint8_t *font, unsigned int ch) { -- cgit v1.1 From 426749a7b79cf735dcd9bd4d134af5224fcf8210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:36 +0400 Subject: ui: remove qemu_pixman_linebuf_copy() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 43c7d8bd449 ("console: add qemu_pixman_linebuf_copy"), it seems it was never used. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-3-marcandre.lureau@redhat.com> --- ui/qemu-pixman.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'ui') diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c index c5053cd..be00a96 100644 --- a/ui/qemu-pixman.c +++ b/ui/qemu-pixman.c @@ -200,14 +200,6 @@ void qemu_pixman_linebuf_fill(pixman_image_t *linebuf, pixman_image_t *fb, x, y, 0, 0, 0, 0, width, 1); } -/* copy linebuf to framebuffer */ -void qemu_pixman_linebuf_copy(pixman_image_t *fb, int width, int x, int y, - pixman_image_t *linebuf) -{ - pixman_image_composite(PIXMAN_OP_SRC, linebuf, NULL, fb, - 0, 0, 0, 0, x, y, width, 1); -} - pixman_image_t *qemu_pixman_mirror_create(pixman_format_code_t format, pixman_image_t *image) { -- cgit v1.1 From 4f2c765ba6b648f406b7d64ebbf0e4eaedf3d8be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:37 +0400 Subject: ui/qmp: move screendump to ui-qmp-cmds.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit console.c unit is over-crowded. This code is specific to the handling of the QMP screendump command, so move it in ui-qmp-cmds. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-4-marcandre.lureau@redhat.com> --- ui/console.c | 212 +++++-------------------------------------------------- ui/ui-qmp-cmds.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 204 insertions(+), 195 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 8da2170..9c17024 100644 --- a/ui/console.c +++ b/ui/console.c @@ -28,8 +28,8 @@ #include "qapi/error.h" #include "qapi/qapi-commands-ui.h" #include "qemu/coroutine.h" -#include "qemu/error-report.h" #include "qemu/fifo8.h" +#include "qemu/error-report.h" #include "qemu/main-loop.h" #include "qemu/module.h" #include "qemu/option.h" @@ -37,11 +37,7 @@ #include "chardev/char.h" #include "trace.h" #include "exec/memory.h" -#include "io/channel-file.h" #include "qom/object.h" -#ifdef CONFIG_PNG -#include -#endif #define DEFAULT_BACKSCROLL 512 #define CONSOLE_CURSOR_PERIOD 500 @@ -239,6 +235,22 @@ void graphic_hw_update(QemuConsole *con) } } +static void graphic_hw_update_bh(void *con) +{ + graphic_hw_update(con); +} + +void qemu_console_co_wait_update(QemuConsole *con) +{ + if (qemu_co_queue_empty(&con->dump_queue)) { + /* Defer the update, it will restart the pending coroutines */ + aio_bh_schedule_oneshot(qemu_get_aio_context(), + graphic_hw_update_bh, con); + } + qemu_co_queue_wait(&con->dump_queue, NULL); + +} + static void graphic_hw_gl_unblock_timer(void *opaque) { warn_report("console: no gl-unblock within one second"); @@ -292,196 +304,6 @@ void graphic_hw_invalidate(QemuConsole *con) } } -#ifdef CONFIG_PNG -/** - * png_save: Take a screenshot as PNG - * - * Saves screendump as a PNG file - * - * Returns true for success or false for error. - * - * @fd: File descriptor for PNG file. - * @image: Image data in pixman format. - * @errp: Pointer to an error. - */ -static bool png_save(int fd, pixman_image_t *image, Error **errp) -{ - int width = pixman_image_get_width(image); - int height = pixman_image_get_height(image); - png_struct *png_ptr; - png_info *info_ptr; - g_autoptr(pixman_image_t) linebuf = - qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width); - uint8_t *buf = (uint8_t *)pixman_image_get_data(linebuf); - FILE *f = fdopen(fd, "wb"); - int y; - if (!f) { - error_setg_errno(errp, errno, - "Failed to create file from file descriptor"); - return false; - } - - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, - NULL, NULL); - if (!png_ptr) { - error_setg(errp, "PNG creation failed. Unable to write struct"); - fclose(f); - return false; - } - - info_ptr = png_create_info_struct(png_ptr); - - if (!info_ptr) { - error_setg(errp, "PNG creation failed. Unable to write info"); - fclose(f); - png_destroy_write_struct(&png_ptr, &info_ptr); - return false; - } - - png_init_io(png_ptr, f); - - png_set_IHDR(png_ptr, info_ptr, width, height, 8, - PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - png_write_info(png_ptr, info_ptr); - - for (y = 0; y < height; ++y) { - qemu_pixman_linebuf_fill(linebuf, image, width, 0, y); - png_write_row(png_ptr, buf); - } - - png_write_end(png_ptr, NULL); - - png_destroy_write_struct(&png_ptr, &info_ptr); - - if (fclose(f) != 0) { - error_setg_errno(errp, errno, - "PNG creation failed. Unable to close file"); - return false; - } - - return true; -} - -#else /* no png support */ - -static bool png_save(int fd, pixman_image_t *image, Error **errp) -{ - error_setg(errp, "Enable PNG support with libpng for screendump"); - return false; -} - -#endif /* CONFIG_PNG */ - -static bool ppm_save(int fd, pixman_image_t *image, Error **errp) -{ - int width = pixman_image_get_width(image); - int height = pixman_image_get_height(image); - g_autoptr(Object) ioc = OBJECT(qio_channel_file_new_fd(fd)); - g_autofree char *header = NULL; - g_autoptr(pixman_image_t) linebuf = NULL; - int y; - - trace_ppm_save(fd, image); - - header = g_strdup_printf("P6\n%d %d\n%d\n", width, height, 255); - if (qio_channel_write_all(QIO_CHANNEL(ioc), - header, strlen(header), errp) < 0) { - return false; - } - - linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width); - for (y = 0; y < height; y++) { - qemu_pixman_linebuf_fill(linebuf, image, width, 0, y); - if (qio_channel_write_all(QIO_CHANNEL(ioc), - (char *)pixman_image_get_data(linebuf), - pixman_image_get_stride(linebuf), errp) < 0) { - return false; - } - } - - return true; -} - -static void graphic_hw_update_bh(void *con) -{ - graphic_hw_update(con); -} - -/* Safety: coroutine-only, concurrent-coroutine safe, main thread only */ -void coroutine_fn -qmp_screendump(const char *filename, const char *device, - bool has_head, int64_t head, - bool has_format, ImageFormat format, Error **errp) -{ - g_autoptr(pixman_image_t) image = NULL; - QemuConsole *con; - DisplaySurface *surface; - int fd; - - if (device) { - con = qemu_console_lookup_by_device_name(device, has_head ? head : 0, - errp); - if (!con) { - return; - } - } else { - if (has_head) { - error_setg(errp, "'head' must be specified together with 'device'"); - return; - } - con = qemu_console_lookup_by_index(0); - if (!con) { - error_setg(errp, "There is no console to take a screendump from"); - return; - } - } - - if (qemu_co_queue_empty(&con->dump_queue)) { - /* Defer the update, it will restart the pending coroutines */ - aio_bh_schedule_oneshot(qemu_get_aio_context(), - graphic_hw_update_bh, con); - } - qemu_co_queue_wait(&con->dump_queue, NULL); - - /* - * All pending coroutines are woken up, while the BQL is held. No - * further graphic update are possible until it is released. Take - * an image ref before that. - */ - surface = qemu_console_surface(con); - if (!surface) { - error_setg(errp, "no surface"); - return; - } - image = pixman_image_ref(surface->image); - - fd = qemu_open_old(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); - if (fd == -1) { - error_setg(errp, "failed to open file '%s': %s", filename, - strerror(errno)); - return; - } - - /* - * The image content could potentially be updated as the coroutine - * yields and releases the BQL. It could produce corrupted dump, but - * it should be otherwise safe. - */ - if (has_format && format == IMAGE_FORMAT_PNG) { - /* PNG format specified for screendump */ - if (!png_save(fd, image, errp)) { - qemu_unlink(filename); - } - } else { - /* PPM format specified/default for screendump */ - if (!ppm_save(fd, image, errp)) { - qemu_unlink(filename); - } - } -} - void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata) { if (!con) { diff --git a/ui/ui-qmp-cmds.c b/ui/ui-qmp-cmds.c index a37a702..debc07d 100644 --- a/ui/ui-qmp-cmds.c +++ b/ui/ui-qmp-cmds.c @@ -14,13 +14,20 @@ */ #include "qemu/osdep.h" + +#include "io/channel-file.h" #include "monitor/qmp-helpers.h" #include "qapi/qapi-commands-ui.h" #include "qapi/qmp/qerror.h" +#include "qemu/coroutine.h" #include "qemu/cutils.h" +#include "trace.h" #include "ui/console.h" #include "ui/dbus-display.h" #include "ui/qemu-spice.h" +#ifdef CONFIG_PNG +#include +#endif void qmp_set_password(SetPasswordOptions *opts, Error **errp) { @@ -204,3 +211,183 @@ void qmp_client_migrate_info(const char *protocol, const char *hostname, error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "protocol", "'spice'"); } + +#ifdef CONFIG_PNG +/** + * png_save: Take a screenshot as PNG + * + * Saves screendump as a PNG file + * + * Returns true for success or false for error. + * + * @fd: File descriptor for PNG file. + * @image: Image data in pixman format. + * @errp: Pointer to an error. + */ +static bool png_save(int fd, pixman_image_t *image, Error **errp) +{ + int width = pixman_image_get_width(image); + int height = pixman_image_get_height(image); + png_struct *png_ptr; + png_info *info_ptr; + g_autoptr(pixman_image_t) linebuf = + qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width); + uint8_t *buf = (uint8_t *)pixman_image_get_data(linebuf); + FILE *f = fdopen(fd, "wb"); + int y; + if (!f) { + error_setg_errno(errp, errno, + "Failed to create file from file descriptor"); + return false; + } + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, + NULL, NULL); + if (!png_ptr) { + error_setg(errp, "PNG creation failed. Unable to write struct"); + fclose(f); + return false; + } + + info_ptr = png_create_info_struct(png_ptr); + + if (!info_ptr) { + error_setg(errp, "PNG creation failed. Unable to write info"); + fclose(f); + png_destroy_write_struct(&png_ptr, &info_ptr); + return false; + } + + png_init_io(png_ptr, f); + + png_set_IHDR(png_ptr, info_ptr, width, height, 8, + PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_write_info(png_ptr, info_ptr); + + for (y = 0; y < height; ++y) { + qemu_pixman_linebuf_fill(linebuf, image, width, 0, y); + png_write_row(png_ptr, buf); + } + + png_write_end(png_ptr, NULL); + + png_destroy_write_struct(&png_ptr, &info_ptr); + + if (fclose(f) != 0) { + error_setg_errno(errp, errno, + "PNG creation failed. Unable to close file"); + return false; + } + + return true; +} + +#else /* no png support */ + +static bool png_save(int fd, pixman_image_t *image, Error **errp) +{ + error_setg(errp, "Enable PNG support with libpng for screendump"); + return false; +} + +#endif /* CONFIG_PNG */ + +static bool ppm_save(int fd, pixman_image_t *image, Error **errp) +{ + int width = pixman_image_get_width(image); + int height = pixman_image_get_height(image); + g_autoptr(Object) ioc = OBJECT(qio_channel_file_new_fd(fd)); + g_autofree char *header = NULL; + g_autoptr(pixman_image_t) linebuf = NULL; + int y; + + trace_ppm_save(fd, image); + + header = g_strdup_printf("P6\n%d %d\n%d\n", width, height, 255); + if (qio_channel_write_all(QIO_CHANNEL(ioc), + header, strlen(header), errp) < 0) { + return false; + } + + linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width); + for (y = 0; y < height; y++) { + qemu_pixman_linebuf_fill(linebuf, image, width, 0, y); + if (qio_channel_write_all(QIO_CHANNEL(ioc), + (char *)pixman_image_get_data(linebuf), + pixman_image_get_stride(linebuf), errp) < 0) { + return false; + } + } + + return true; +} + +/* Safety: coroutine-only, concurrent-coroutine safe, main thread only */ +void coroutine_fn +qmp_screendump(const char *filename, const char *device, + bool has_head, int64_t head, + bool has_format, ImageFormat format, Error **errp) +{ + g_autoptr(pixman_image_t) image = NULL; + QemuConsole *con; + DisplaySurface *surface; + int fd; + + if (device) { + con = qemu_console_lookup_by_device_name(device, has_head ? head : 0, + errp); + if (!con) { + return; + } + } else { + if (has_head) { + error_setg(errp, "'head' must be specified together with 'device'"); + return; + } + con = qemu_console_lookup_by_index(0); + if (!con) { + error_setg(errp, "There is no console to take a screendump from"); + return; + } + } + + qemu_console_co_wait_update(con); + + /* + * All pending coroutines are woken up, while the BQL is held. No + * further graphic update are possible until it is released. Take + * an image ref before that. + */ + surface = qemu_console_surface(con); + if (!surface) { + error_setg(errp, "no surface"); + return; + } + image = pixman_image_ref(surface->image); + + fd = qemu_open_old(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + if (fd == -1) { + error_setg(errp, "failed to open file '%s': %s", filename, + strerror(errno)); + return; + } + + /* + * The image content could potentially be updated as the coroutine + * yields and releases the BQL. It could produce corrupted dump, but + * it should be otherwise safe. + */ + if (has_format && format == IMAGE_FORMAT_PNG) { + /* PNG format specified for screendump */ + if (!png_save(fd, image, errp)) { + qemu_unlink(filename); + } + } else { + /* PPM format specified/default for screendump */ + if (!ppm_save(fd, image, errp)) { + qemu_unlink(filename); + } + } +} -- cgit v1.1 From f1f7a1e2cfee7beee626552744efcc5a3867501f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:38 +0400 Subject: ui/vc: replace vc_chr_write() with generic qemu_chr_write() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We shouldn't call the callback directly, but use the chardev API, unless there is a clear reason. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230830093843.3531473-5-marcandre.lureau@redhat.com> --- ui/console.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 9c17024..a448e4d 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1169,13 +1169,13 @@ void kbd_put_keysym_console(QemuConsole *s, int keysym) *q++ = '['; *q++ = keysym & 0xff; } else if (s->echo && (keysym == '\r' || keysym == '\n')) { - vc_chr_write(s->chr, (const uint8_t *) "\r", 1); + qemu_chr_write(s->chr, (uint8_t *)"\r", 1, true); *q++ = '\n'; } else { *q++ = keysym; } if (s->echo) { - vc_chr_write(s->chr, buf, q - buf); + qemu_chr_write(s->chr, buf, q - buf, true); } num_free = fifo8_num_free(&s->out_fifo); fifo8_push_all(&s->out_fifo, buf, MIN(num_free, q - buf)); @@ -2474,7 +2474,7 @@ static void text_console_do_init(Chardev *chr, DisplayState *ds) s->t_attrib.bgcol = QEMU_COLOR_BLUE; msg = g_strdup_printf("%s console\r\n", chr->label); - vc_chr_write(chr, (uint8_t *)msg, strlen(msg)); + qemu_chr_write(chr, (uint8_t *)msg, strlen(msg), true); g_free(msg); s->t_attrib = s->t_attrib_default; } -- cgit v1.1 From 177422789be54447cfc2d770145968058e5d0b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:39 +0400 Subject: ui/vc: drop have_text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If there are no "text" listener, the callback will simply be ignored. The rest of text handling can be done cheaply. This allows to remove some dependency on DisplayState from VC implementation. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-6-marcandre.lureau@redhat.com> --- ui/console.c | 42 +++++++++++++----------------------------- 1 file changed, 13 insertions(+), 29 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index a448e4d..bec2d1a 100644 --- a/ui/console.c +++ b/ui/console.c @@ -133,7 +133,6 @@ struct DisplayState { uint64_t update_interval; bool refreshing; bool have_gfx; - bool have_text; QLIST_HEAD(, DisplayChangeListener) listeners; }; @@ -185,7 +184,6 @@ static void gui_setup_refresh(DisplayState *ds) 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) { @@ -194,9 +192,6 @@ static void gui_setup_refresh(DisplayState *ds) if (dcl->ops->dpy_gfx_update != NULL) { have_gfx = true; } - if (dcl->ops->dpy_text_update != NULL) { - have_text = true; - } } if (need_timer && ds->gui_timer == NULL) { @@ -209,7 +204,6 @@ static void gui_setup_refresh(DisplayState *ds) } ds->have_gfx = have_gfx; - ds->have_text = have_text; } void graphic_hw_update_done(QemuConsole *con) @@ -456,9 +450,7 @@ static void update_xy(QemuConsole *s, int x, int y) TextCell *c; int y1, y2; - if (s->ds->have_text) { - text_update_xy(s, x, y); - } + text_update_xy(s, x, y); y1 = (s->y_base + y) % s->total_height; y2 = y1 - s->y_displayed; @@ -482,9 +474,7 @@ static void console_show_cursor(QemuConsole *s, int show) int y, y1; int x = s->x; - if (s->ds->have_text) { - s->cursor_invalidate = 1; - } + s->cursor_invalidate = 1; if (x >= s->width) { x = s->width - 1; @@ -513,13 +503,11 @@ static void console_refresh(QemuConsole *s) TextCell *c; int x, y, y1; - 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; - s->cursor_invalidate = 1; - } + 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]); @@ -594,12 +582,10 @@ static void console_put_lf(QemuConsole *s) c++; } if (s->y_displayed == s->y_base) { - 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; - } + s->text_x[0] = 0; + s->text_y[0] = 0; + 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, @@ -1069,9 +1055,7 @@ void console_select(unsigned int index) displaychangelistener_display_console(dcl, s, NULL); } } - if (ds->have_text) { - dpy_text_resize(s, s->width, s->height); - } + dpy_text_resize(s, s->width, s->height); text_console_update_cursor(NULL); } } @@ -1239,7 +1223,7 @@ static void text_console_invalidate(void *opaque) { QemuConsole *s = (QemuConsole *) opaque; - if (s->ds->have_text && s->console_type == TEXT_CONSOLE) { + if (s->console_type == TEXT_CONSOLE) { text_console_resize(s); } console_refresh(s); -- cgit v1.1 From 074b24094f34c3241956064cf7910bbe11642871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:40 +0400 Subject: ui/console: console_select() regardless of have_gfx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even if we don't have a gfx listener, we should call displaychangelistener_display_console() which handle that case correctly. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-7-marcandre.lureau@redhat.com> --- ui/console.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index bec2d1a..14717a6 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1047,13 +1047,11 @@ void console_select(unsigned int index) DisplayState *ds = s->ds; active_console = s; - if (ds->have_gfx) { - QLIST_FOREACH(dcl, &ds->listeners, next) { - if (dcl->con != NULL) { - continue; - } - displaychangelistener_display_console(dcl, s, NULL); + QLIST_FOREACH (dcl, &ds->listeners, next) { + if (dcl->con != NULL) { + continue; } + displaychangelistener_display_console(dcl, s, NULL); } dpy_text_resize(s, s->width, s->height); text_console_update_cursor(NULL); -- cgit v1.1 From bc9b8bc93cafee6f3c9f73ef5e8a7379004e8699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:41 +0400 Subject: ui/console: call dpy_gfx_update() regardless of have_gfx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function will handle the case when no listeners are gfx, without extra meaningful cost. This allows to get rid of DisplayState dependency in VC implementation. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-8-marcandre.lureau@redhat.com> --- ui/console.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 14717a6..2bc4c15 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1087,7 +1087,7 @@ static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len) console_putchar(s, buf[i]); } console_show_cursor(s, 1); - if (s->ds->have_gfx && s->update_x0 < s->update_x1) { + if (s->update_x0 < s->update_x1) { dpy_gfx_update(s, s->update_x0, s->update_y0, s->update_x1 - s->update_x0, s->update_y1 - s->update_y0); -- cgit v1.1 From cbcf0fa8fd9723ee51af803bf58a8d6d3e6a4194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:42 +0400 Subject: ui/console: drop have_gfx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All usages have been removed. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-9-marcandre.lureau@redhat.com> --- ui/console.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 2bc4c15..fc18367 100644 --- a/ui/console.c +++ b/ui/console.c @@ -132,7 +132,6 @@ struct DisplayState { uint64_t last_update; uint64_t update_interval; bool refreshing; - bool have_gfx; QLIST_HEAD(, DisplayChangeListener) listeners; }; @@ -183,15 +182,11 @@ static void gui_setup_refresh(DisplayState *ds) { DisplayChangeListener *dcl; bool need_timer = false; - bool have_gfx = 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 (need_timer && ds->gui_timer == NULL) { @@ -202,8 +197,6 @@ static void gui_setup_refresh(DisplayState *ds) timer_free(ds->gui_timer); ds->gui_timer = NULL; } - - ds->have_gfx = have_gfx; } void graphic_hw_update_done(QemuConsole *con) -- cgit v1.1 From 2fd319cff0ffbc0b54a61a2a34775ec40836e4c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:43 +0400 Subject: ui/console: get the DisplayState from new_console() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no obvious reason to defer text console initialization. We can simply take the global display state in new_console(). This simplify somewhat the code to allow moving the VC to a separate unit. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-10-marcandre.lureau@redhat.com> --- ui/console.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index fc18367..24cfd31 100644 --- a/ui/console.c +++ b/ui/console.c @@ -143,7 +143,7 @@ static QTAILQ_HEAD(, QemuConsole) consoles = static bool cursor_visible_phase; static QEMUTimer *cursor_timer; -static void text_console_do_init(Chardev *chr, DisplayState *ds); +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); @@ -1249,9 +1249,9 @@ static void text_console_update(void *opaque, console_ch_t *chardata) } } -static QemuConsole *new_console(DisplayState *ds, console_type_t console_type, - uint32_t head) +static QemuConsole *new_console(console_type_t console_type, uint32_t head) { + DisplayState *ds = get_alloc_displaystate(); Object *obj; QemuConsole *s; int i; @@ -2049,13 +2049,7 @@ DisplayState *init_displaystate(void) gchar *name; QemuConsole *con; - get_alloc_displaystate(); QTAILQ_FOREACH(con, &consoles, next) { - if (con->console_type != GRAPHIC_CONSOLE && - con->ds == NULL) { - text_console_do_init(con->chr, display_state); - } - /* Hook up into the qom tree here (not in new_console()), once * all QemuConsoles are created and the order / numbering * doesn't change any more */ @@ -2085,10 +2079,8 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head, int width = 640; int height = 480; QemuConsole *s; - DisplayState *ds; DisplaySurface *surface; - ds = get_alloc_displaystate(); s = qemu_console_lookup_unused(); if (s) { trace_console_gfx_reuse(s->index); @@ -2096,7 +2088,7 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head, height = qemu_console_get_height(s, 0); } else { trace_console_gfx_new(); - s = new_console(ds, GRAPHIC_CONSOLE, head); + s = new_console(GRAPHIC_CONSOLE, head); s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, dpy_set_ui_info_timer, s); } @@ -2405,7 +2397,7 @@ static const GraphicHwOps text_console_ops = { .text_update = text_console_update, }; -static void text_console_do_init(Chardev *chr, DisplayState *ds) +static void text_console_do_init(Chardev *chr) { VCChardev *drv = VC_CHARDEV(chr); QemuConsole *s = drv->console; @@ -2413,7 +2405,6 @@ static void text_console_do_init(Chardev *chr, DisplayState *ds) int g_height = 24 * FONT_HEIGHT; fifo8_create(&s->out_fifo, 16); - s->ds = ds; s->y_displayed = 0; s->y_base = 0; @@ -2482,9 +2473,9 @@ static void vc_chr_open(Chardev *chr, trace_console_txt_new(width, height); if (width == 0 || height == 0) { - s = new_console(NULL, TEXT_CONSOLE, 0); + s = new_console(TEXT_CONSOLE, 0); } else { - s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0); + s = new_console(TEXT_CONSOLE_FIXED_SIZE, 0); s->scanout.kind = SCANOUT_SURFACE; s->surface = qemu_create_displaysurface(width, height); } @@ -2497,9 +2488,7 @@ static void vc_chr_open(Chardev *chr, s->chr = chr; drv->console = s; - if (display_state) { - text_console_do_init(chr, display_state); - } + text_console_do_init(chr); /* console/chardev init sometimes completes elsewhere in a 2nd * stage, so defer OPENED events until they are fully initialized -- cgit v1.1 From dc6984bdc3ebe5357b0c1d983ba4e7689a985f2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:44 +0400 Subject: ui/console: new_console() cannot fail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no code path that could allow a NULL return there. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-11-marcandre.lureau@redhat.com> --- ui/console.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 24cfd31..ddec68f 100644 --- a/ui/console.c +++ b/ui/console.c @@ -2480,11 +2480,6 @@ static void vc_chr_open(Chardev *chr, s->surface = qemu_create_displaysurface(width, height); } - if (!s) { - error_setg(errp, "cannot create text console"); - return; - } - s->chr = chr; drv->console = s; -- cgit v1.1 From 6657e41cde73597e61c0165da7be7e76f116f342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:45 +0400 Subject: ui/vc: VC always has a DisplayState now MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-12-marcandre.lureau@redhat.com> --- ui/console.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index ddec68f..f97db29 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1067,10 +1067,6 @@ static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len) QemuConsole *s = drv->console; int i; - if (!s->ds) { - return 0; - } - s->update_x0 = s->width * FONT_WIDTH; s->update_y0 = s->height * FONT_HEIGHT; s->update_x1 = 0; -- cgit v1.1 From 8c63667b25cf377fa6ef46149ac55dc7e9e553db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:46 +0400 Subject: ui/vc: move VCChardev declaration at the top MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To allow easier refactoring in following patches. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-13-marcandre.lureau@redhat.com> --- ui/console.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index f97db29..5c8e3ad 100644 --- a/ui/console.c +++ b/ui/console.c @@ -127,6 +127,12 @@ struct QemuConsole { QTAILQ_ENTRY(QemuConsole) next; }; +struct VCChardev { + Chardev parent; + QemuConsole *console; +}; +typedef struct VCChardev VCChardev; + struct DisplayState { QEMUTimer *gui_timer; uint64_t last_update; @@ -1051,12 +1057,6 @@ void console_select(unsigned int index) } } -struct VCChardev { - Chardev parent; - QemuConsole *console; -}; -typedef struct VCChardev VCChardev; - #define TYPE_CHARDEV_VC "chardev-vc" DECLARE_INSTANCE_CHECKER(VCChardev, VC_CHARDEV, TYPE_CHARDEV_VC) -- cgit v1.1 From 3be82c6a3a983cd382aad2200fede5ec304dbc1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:47 +0400 Subject: ui/vc: replace variable with static text attributes default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-14-marcandre.lureau@redhat.com> --- ui/console.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 5c8e3ad..d1855f3 100644 --- a/ui/console.c +++ b/ui/console.c @@ -52,6 +52,11 @@ typedef struct TextAttributes { uint8_t unvisible:1; } TextAttributes; +#define TEXT_ATTRIBUTES_DEFAULT ((TextAttributes) { \ + .fgcol = QEMU_COLOR_WHITE, \ + .bgcol = QEMU_COLOR_BLACK \ +}) + typedef struct TextCell { uint8_t ch; TextAttributes t_attrib; @@ -104,7 +109,6 @@ struct QemuConsole { int x_saved, y_saved; int y_displayed; int y_base; - TextAttributes t_attrib_default; /* default text attributes */ TextAttributes t_attrib; /* currently active text attributes */ TextCell *cells; int text_x[2], text_y[2], cursor_invalidate; @@ -413,7 +417,7 @@ static void text_console_resize(QemuConsole *s) } for(x = w1; x < s->width; x++) { c->ch = ' '; - c->t_attrib = s->t_attrib_default; + c->t_attrib = TEXT_ATTRIBUTES_DEFAULT; c++; } } @@ -486,7 +490,7 @@ static void console_show_cursor(QemuConsole *s, int show) if (y < s->height) { c = &s->cells[y1 * s->width + x]; if (show && cursor_visible_phase) { - TextAttributes t_attrib = s->t_attrib_default; + 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); } else { @@ -577,7 +581,7 @@ static void console_put_lf(QemuConsole *s) c = &s->cells[y1 * s->width]; for(x = 0; x < s->width; x++) { c->ch = ' '; - c->t_attrib = s->t_attrib_default; + c->t_attrib = TEXT_ATTRIBUTES_DEFAULT; c++; } if (s->y_displayed == s->y_base) { @@ -591,7 +595,7 @@ static void console_put_lf(QemuConsole *s) (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]); + color_table_rgb[0][TEXT_ATTRIBUTES_DEFAULT.bgcol]); s->update_x0 = 0; s->update_y0 = 0; s->update_x1 = s->width * FONT_WIDTH; @@ -611,7 +615,7 @@ static void console_handle_escape(QemuConsole *s) for (i=0; inb_esc_params; i++) { switch (s->esc_params[i]) { case 0: /* reset all console attributes to default */ - s->t_attrib = s->t_attrib_default; + s->t_attrib = TEXT_ATTRIBUTES_DEFAULT; break; case 1: s->t_attrib.bold = 1; @@ -705,7 +709,7 @@ static void console_clear_xy(QemuConsole *s, int x, int y) } TextCell *c = &s->cells[y1 * s->width + x]; c->ch = ' '; - c->t_attrib = s->t_attrib_default; + c->t_attrib = TEXT_ATTRIBUTES_DEFAULT; update_xy(s, x, y); } @@ -2419,16 +2423,8 @@ static void text_console_do_init(Chardev *chr) s->hw_ops = &text_console_ops; s->hw = s; - /* Set text attribute defaults */ - s->t_attrib_default.bold = 0; - s->t_attrib_default.uline = 0; - s->t_attrib_default.blink = 0; - s->t_attrib_default.invers = 0; - s->t_attrib_default.unvisible = 0; - s->t_attrib_default.fgcol = QEMU_COLOR_WHITE; - s->t_attrib_default.bgcol = QEMU_COLOR_BLACK; /* set current text attributes to default */ - s->t_attrib = s->t_attrib_default; + s->t_attrib = TEXT_ATTRIBUTES_DEFAULT; text_console_resize(s); if (chr->label) { @@ -2438,7 +2434,7 @@ static void text_console_do_init(Chardev *chr) msg = g_strdup_printf("%s console\r\n", chr->label); qemu_chr_write(chr, (uint8_t *)msg, strlen(msg), true); g_free(msg); - s->t_attrib = s->t_attrib_default; + s->t_attrib = TEXT_ATTRIBUTES_DEFAULT; } qemu_chr_be_event(chr, CHR_EVENT_OPENED); -- cgit v1.1 From d7c634aadf83e029b70b5d508fbfda4671e206d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:48 +0400 Subject: ui/vc: fold text_update_xy() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-15-marcandre.lureau@redhat.com> --- ui/console.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index d1855f3..405aedf 100644 --- a/ui/console.c +++ b/ui/console.c @@ -425,14 +425,6 @@ static void text_console_resize(QemuConsole *s) s->cells = cells; } -static inline void text_update_xy(QemuConsole *s, int x, int y) -{ - s->text_x[0] = MIN(s->text_x[0], x); - s->text_x[1] = MAX(s->text_x[1], x); - s->text_y[0] = MIN(s->text_y[0], y); - s->text_y[1] = MAX(s->text_y[1], y); -} - static void invalidate_xy(QemuConsole *s, int x, int y) { if (!qemu_console_is_visible(s)) { @@ -453,7 +445,10 @@ static void update_xy(QemuConsole *s, int x, int y) TextCell *c; int y1, y2; - text_update_xy(s, x, y); + s->text_x[0] = MIN(s->text_x[0], x); + s->text_x[1] = MAX(s->text_x[1], x); + s->text_y[0] = MIN(s->text_y[0], y); + s->text_y[1] = MAX(s->text_y[1], y); y1 = (s->y_base + y) % s->total_height; y2 = y1 - s->y_displayed; -- cgit v1.1 From 4c946b7f97e09e625d8c359f06f6b3e1ce937e89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:49 +0400 Subject: ui/vc: pass VCCharDev to VC-specific functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even though they actually use more of QemuConsole at this point, it makes it clearer those functions are only used from the chardev implementation. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-16-marcandre.lureau@redhat.com> --- ui/console.c | 70 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 31 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 405aedf..f9ed012 100644 --- a/ui/console.c +++ b/ui/console.c @@ -440,8 +440,9 @@ static void invalidate_xy(QemuConsole *s, int x, int y) s->update_y1 = (y + 1) * FONT_HEIGHT; } -static void update_xy(QemuConsole *s, int x, int y) +static void vc_update_xy(VCChardev *vc, int x, int y) { + QemuConsole *s = vc->console; TextCell *c; int y1, y2; @@ -555,8 +556,9 @@ static void console_scroll(QemuConsole *s, int ydelta) console_refresh(s); } -static void console_put_lf(QemuConsole *s) +static void vc_put_lf(VCChardev *vc) { + QemuConsole *s = vc->console; TextCell *c; int x, y1; @@ -603,8 +605,9 @@ static void console_put_lf(QemuConsole *s) * NOTE: I know this code is not very efficient (checking every color for it * self) but it is more readable and better maintainable. */ -static void console_handle_escape(QemuConsole *s) +static void vc_handle_escape(VCChardev *vc) { + QemuConsole *s = vc->console; int i; for (i=0; inb_esc_params; i++) { @@ -696,8 +699,9 @@ static void console_handle_escape(QemuConsole *s) } } -static void console_clear_xy(QemuConsole *s, int x, int y) +static void vc_clear_xy(VCChardev *vc, int x, int y) { + QemuConsole *s = vc->console; int y1 = (s->y_base + y) % s->total_height; if (x >= s->width) { x = s->width - 1; @@ -705,37 +709,40 @@ static void console_clear_xy(QemuConsole *s, int x, int y) TextCell *c = &s->cells[y1 * s->width + x]; c->ch = ' '; c->t_attrib = TEXT_ATTRIBUTES_DEFAULT; - update_xy(s, x, y); + vc_update_xy(vc, x, y); } -static void console_put_one(QemuConsole *s, int ch) +static void vc_put_one(VCChardev *vc, int ch) { + QemuConsole *s = vc->console; TextCell *c; int y1; if (s->x >= s->width) { /* line wrap */ s->x = 0; - console_put_lf(s); + vc_put_lf(vc); } y1 = (s->y_base + s->y) % s->total_height; c = &s->cells[y1 * s->width + s->x]; c->ch = ch; c->t_attrib = s->t_attrib; - update_xy(s, s->x, s->y); + vc_update_xy(vc, s->x, s->y); s->x++; } -static void console_respond_str(QemuConsole *s, const char *buf) +static void vc_respond_str(VCChardev *vc, const char *buf) { while (*buf) { - console_put_one(s, *buf); + vc_put_one(vc, *buf); buf++; } } /* set cursor, checking bounds */ -static void set_cursor(QemuConsole *s, int x, int y) +static void vc_set_cursor(VCChardev *vc, int x, int y) { + QemuConsole *s = vc->console; + if (x < 0) { x = 0; } @@ -753,8 +760,9 @@ static void set_cursor(QemuConsole *s, int x, int y) s->y = y; } -static void console_putchar(QemuConsole *s, int ch) +static void vc_putchar(VCChardev *vc, int ch) { + QemuConsole *s = vc->console; int i; int x, y; char response[40]; @@ -766,7 +774,7 @@ static void console_putchar(QemuConsole *s, int ch) s->x = 0; break; case '\n': /* newline */ - console_put_lf(s); + vc_put_lf(vc); break; case '\b': /* backspace */ if (s->x > 0) @@ -775,7 +783,7 @@ static void console_putchar(QemuConsole *s, int ch) case '\t': /* tabspace */ if (s->x + (8 - (s->x % 8)) > s->width) { s->x = 0; - console_put_lf(s); + vc_put_lf(vc); } else { s->x = s->x + (8 - (s->x % 8)); } @@ -793,7 +801,7 @@ static void console_putchar(QemuConsole *s, int ch) s->state = TTY_STATE_ESC; break; default: - console_put_one(s, ch); + vc_put_one(vc, ch); break; } break; @@ -831,37 +839,37 @@ static void console_putchar(QemuConsole *s, int ch) if (s->esc_params[0] == 0) { s->esc_params[0] = 1; } - set_cursor(s, s->x, s->y - s->esc_params[0]); + vc_set_cursor(vc, 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; } - set_cursor(s, s->x, s->y + s->esc_params[0]); + vc_set_cursor(vc, 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; } - set_cursor(s, s->x + s->esc_params[0], s->y); + vc_set_cursor(vc, 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; } - set_cursor(s, s->x - s->esc_params[0], s->y); + vc_set_cursor(vc, s->x - s->esc_params[0], s->y); break; case 'G': /* move cursor to column */ - set_cursor(s, s->esc_params[0] - 1, s->y); + vc_set_cursor(vc, s->esc_params[0] - 1, s->y); break; case 'f': case 'H': /* move cursor to row, column */ - set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1); + vc_set_cursor(vc, s->esc_params[1] - 1, s->esc_params[0] - 1); break; case 'J': switch (s->esc_params[0]) { @@ -872,7 +880,7 @@ static void console_putchar(QemuConsole *s, int ch) if (y == s->y && x < s->x) { continue; } - console_clear_xy(s, x, y); + vc_clear_xy(vc, x, y); } } break; @@ -883,7 +891,7 @@ static void console_putchar(QemuConsole *s, int ch) if (y == s->y && x > s->x) { break; } - console_clear_xy(s, x, y); + vc_clear_xy(vc, x, y); } } break; @@ -891,7 +899,7 @@ static void console_putchar(QemuConsole *s, int ch) /* clear entire screen */ for (y = 0; y <= s->height; y++) { for (x = 0; x < s->width; x++) { - console_clear_xy(s, x, y); + vc_clear_xy(vc, x, y); } } break; @@ -902,38 +910,38 @@ static void console_putchar(QemuConsole *s, int ch) case 0: /* clear to eol */ for(x = s->x; x < s->width; x++) { - console_clear_xy(s, x, s->y); + vc_clear_xy(vc, x, s->y); } break; case 1: /* clear from beginning of line */ for (x = 0; x <= s->x && x < s->width; x++) { - console_clear_xy(s, x, s->y); + vc_clear_xy(vc, x, s->y); } break; case 2: /* clear entire line */ for(x = 0; x < s->width; x++) { - console_clear_xy(s, x, s->y); + vc_clear_xy(vc, x, s->y); } break; } break; case 'm': - console_handle_escape(s); + vc_handle_escape(vc); break; case 'n': switch (s->esc_params[0]) { case 5: /* report console status (always succeed)*/ - console_respond_str(s, "\033[0n"); + vc_respond_str(vc, "\033[0n"); break; case 6: /* report cursor position */ sprintf(response, "\033[%d;%dR", (s->y_base + s->y) % s->total_height + 1, s->x + 1); - console_respond_str(s, response); + vc_respond_str(vc, response); break; } break; @@ -1072,7 +1080,7 @@ static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len) s->update_y1 = 0; console_show_cursor(s, 0); for(i = 0; i < len; i++) { - console_putchar(s, buf[i]); + vc_putchar(drv, buf[i]); } console_show_cursor(s, 1); if (s->update_x0 < s->update_x1) { -- cgit v1.1 From 6505fd8d2390e57c6a2e84f9c07b9e408ad7da76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:50 +0400 Subject: ui/vc: move VCCharDev specific fields out of QemuConsole MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-17-marcandre.lureau@redhat.com> --- ui/console.c | 147 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 73 insertions(+), 74 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index f9ed012..1336a1b 100644 --- a/ui/console.c +++ b/ui/console.c @@ -106,10 +106,8 @@ struct QemuConsole { int total_height; int backscroll_height; int x, y; - int x_saved, y_saved; int y_displayed; int y_base; - TextAttributes t_attrib; /* currently active text attributes */ TextCell *cells; int text_x[2], text_y[2], cursor_invalidate; int echo; @@ -119,10 +117,6 @@ struct QemuConsole { int update_x1; int update_y1; - enum TTYState state; - int esc_params[MAX_ESC_PARAMS]; - int nb_esc_params; - Chardev *chr; /* fifo for key pressed */ Fifo8 out_fifo; @@ -134,6 +128,12 @@ struct QemuConsole { struct VCChardev { Chardev parent; QemuConsole *console; + + enum TTYState state; + int esc_params[MAX_ESC_PARAMS]; + int nb_esc_params; + TextAttributes t_attrib; /* currently active text attributes */ + int x_saved, y_saved; }; typedef struct VCChardev VCChardev; @@ -607,93 +607,92 @@ static void vc_put_lf(VCChardev *vc) */ static void vc_handle_escape(VCChardev *vc) { - QemuConsole *s = vc->console; int i; - for (i=0; inb_esc_params; i++) { - switch (s->esc_params[i]) { + for (i = 0; i < vc->nb_esc_params; i++) { + switch (vc->esc_params[i]) { case 0: /* reset all console attributes to default */ - s->t_attrib = TEXT_ATTRIBUTES_DEFAULT; + vc->t_attrib = TEXT_ATTRIBUTES_DEFAULT; break; case 1: - s->t_attrib.bold = 1; + vc->t_attrib.bold = 1; break; case 4: - s->t_attrib.uline = 1; + vc->t_attrib.uline = 1; break; case 5: - s->t_attrib.blink = 1; + vc->t_attrib.blink = 1; break; case 7: - s->t_attrib.invers = 1; + vc->t_attrib.invers = 1; break; case 8: - s->t_attrib.unvisible = 1; + vc->t_attrib.unvisible = 1; break; case 22: - s->t_attrib.bold = 0; + vc->t_attrib.bold = 0; break; case 24: - s->t_attrib.uline = 0; + vc->t_attrib.uline = 0; break; case 25: - s->t_attrib.blink = 0; + vc->t_attrib.blink = 0; break; case 27: - s->t_attrib.invers = 0; + vc->t_attrib.invers = 0; break; case 28: - s->t_attrib.unvisible = 0; + vc->t_attrib.unvisible = 0; break; /* set foreground color */ case 30: - s->t_attrib.fgcol = QEMU_COLOR_BLACK; + vc->t_attrib.fgcol = QEMU_COLOR_BLACK; break; case 31: - s->t_attrib.fgcol = QEMU_COLOR_RED; + vc->t_attrib.fgcol = QEMU_COLOR_RED; break; case 32: - s->t_attrib.fgcol = QEMU_COLOR_GREEN; + vc->t_attrib.fgcol = QEMU_COLOR_GREEN; break; case 33: - s->t_attrib.fgcol = QEMU_COLOR_YELLOW; + vc->t_attrib.fgcol = QEMU_COLOR_YELLOW; break; case 34: - s->t_attrib.fgcol = QEMU_COLOR_BLUE; + vc->t_attrib.fgcol = QEMU_COLOR_BLUE; break; case 35: - s->t_attrib.fgcol = QEMU_COLOR_MAGENTA; + vc->t_attrib.fgcol = QEMU_COLOR_MAGENTA; break; case 36: - s->t_attrib.fgcol = QEMU_COLOR_CYAN; + vc->t_attrib.fgcol = QEMU_COLOR_CYAN; break; case 37: - s->t_attrib.fgcol = QEMU_COLOR_WHITE; + vc->t_attrib.fgcol = QEMU_COLOR_WHITE; break; /* set background color */ case 40: - s->t_attrib.bgcol = QEMU_COLOR_BLACK; + vc->t_attrib.bgcol = QEMU_COLOR_BLACK; break; case 41: - s->t_attrib.bgcol = QEMU_COLOR_RED; + vc->t_attrib.bgcol = QEMU_COLOR_RED; break; case 42: - s->t_attrib.bgcol = QEMU_COLOR_GREEN; + vc->t_attrib.bgcol = QEMU_COLOR_GREEN; break; case 43: - s->t_attrib.bgcol = QEMU_COLOR_YELLOW; + vc->t_attrib.bgcol = QEMU_COLOR_YELLOW; break; case 44: - s->t_attrib.bgcol = QEMU_COLOR_BLUE; + vc->t_attrib.bgcol = QEMU_COLOR_BLUE; break; case 45: - s->t_attrib.bgcol = QEMU_COLOR_MAGENTA; + vc->t_attrib.bgcol = QEMU_COLOR_MAGENTA; break; case 46: - s->t_attrib.bgcol = QEMU_COLOR_CYAN; + vc->t_attrib.bgcol = QEMU_COLOR_CYAN; break; case 47: - s->t_attrib.bgcol = QEMU_COLOR_WHITE; + vc->t_attrib.bgcol = QEMU_COLOR_WHITE; break; } } @@ -725,7 +724,7 @@ static void vc_put_one(VCChardev *vc, int ch) y1 = (s->y_base + s->y) % s->total_height; c = &s->cells[y1 * s->width + s->x]; c->ch = ch; - c->t_attrib = s->t_attrib; + c->t_attrib = vc->t_attrib; vc_update_xy(vc, s->x, s->y); s->x++; } @@ -767,7 +766,7 @@ static void vc_putchar(VCChardev *vc, int ch) int x, y; char response[40]; - switch(s->state) { + switch(vc->state) { case TTY_STATE_NORM: switch(ch) { case '\r': /* carriage return */ @@ -798,7 +797,7 @@ static void vc_putchar(VCChardev *vc, int ch) /* SO (shift out), character set 1 (ignored) */ break; case 27: /* esc (introducing an escape sequence) */ - s->state = TTY_STATE_ESC; + vc->state = TTY_STATE_ESC; break; default: vc_put_one(vc, ch); @@ -808,71 +807,71 @@ static void vc_putchar(VCChardev *vc, int ch) case TTY_STATE_ESC: /* check if it is a terminal escape sequence */ if (ch == '[') { for(i=0;iesc_params[i] = 0; - s->nb_esc_params = 0; - s->state = TTY_STATE_CSI; + vc->esc_params[i] = 0; + vc->nb_esc_params = 0; + vc->state = TTY_STATE_CSI; } else { - s->state = TTY_STATE_NORM; + vc->state = TTY_STATE_NORM; } break; case TTY_STATE_CSI: /* handle escape sequence parameters */ if (ch >= '0' && ch <= '9') { - if (s->nb_esc_params < MAX_ESC_PARAMS) { - int *param = &s->esc_params[s->nb_esc_params]; + if (vc->nb_esc_params < MAX_ESC_PARAMS) { + int *param = &vc->esc_params[vc->nb_esc_params]; int digit = (ch - '0'); *param = (*param <= (INT_MAX - digit) / 10) ? *param * 10 + digit : INT_MAX; } } else { - if (s->nb_esc_params < MAX_ESC_PARAMS) - s->nb_esc_params++; + if (vc->nb_esc_params < MAX_ESC_PARAMS) + vc->nb_esc_params++; if (ch == ';' || ch == '?') { break; } - trace_console_putchar_csi(s->esc_params[0], s->esc_params[1], - ch, s->nb_esc_params); - s->state = TTY_STATE_NORM; + trace_console_putchar_csi(vc->esc_params[0], vc->esc_params[1], + ch, vc->nb_esc_params); + vc->state = TTY_STATE_NORM; switch(ch) { case 'A': /* move cursor up */ - if (s->esc_params[0] == 0) { - s->esc_params[0] = 1; + if (vc->esc_params[0] == 0) { + vc->esc_params[0] = 1; } - vc_set_cursor(vc, s->x, s->y - s->esc_params[0]); + vc_set_cursor(vc, s->x, s->y - vc->esc_params[0]); break; case 'B': /* move cursor down */ - if (s->esc_params[0] == 0) { - s->esc_params[0] = 1; + if (vc->esc_params[0] == 0) { + vc->esc_params[0] = 1; } - vc_set_cursor(vc, s->x, s->y + s->esc_params[0]); + vc_set_cursor(vc, s->x, s->y + vc->esc_params[0]); break; case 'C': /* move cursor right */ - if (s->esc_params[0] == 0) { - s->esc_params[0] = 1; + if (vc->esc_params[0] == 0) { + vc->esc_params[0] = 1; } - vc_set_cursor(vc, s->x + s->esc_params[0], s->y); + vc_set_cursor(vc, s->x + vc->esc_params[0], s->y); break; case 'D': /* move cursor left */ - if (s->esc_params[0] == 0) { - s->esc_params[0] = 1; + if (vc->esc_params[0] == 0) { + vc->esc_params[0] = 1; } - vc_set_cursor(vc, s->x - s->esc_params[0], s->y); + vc_set_cursor(vc, s->x - vc->esc_params[0], s->y); break; case 'G': /* move cursor to column */ - vc_set_cursor(vc, s->esc_params[0] - 1, s->y); + vc_set_cursor(vc, vc->esc_params[0] - 1, s->y); break; case 'f': case 'H': /* move cursor to row, column */ - vc_set_cursor(vc, s->esc_params[1] - 1, s->esc_params[0] - 1); + vc_set_cursor(vc, vc->esc_params[1] - 1, vc->esc_params[0] - 1); break; case 'J': - switch (s->esc_params[0]) { + switch (vc->esc_params[0]) { case 0: /* clear to end of screen */ for (y = s->y; y < s->height; y++) { @@ -906,7 +905,7 @@ static void vc_putchar(VCChardev *vc, int ch) } break; case 'K': - switch (s->esc_params[0]) { + switch (vc->esc_params[0]) { case 0: /* clear to eol */ for(x = s->x; x < s->width; x++) { @@ -931,7 +930,7 @@ static void vc_putchar(VCChardev *vc, int ch) vc_handle_escape(vc); break; case 'n': - switch (s->esc_params[0]) { + switch (vc->esc_params[0]) { case 5: /* report console status (always succeed)*/ vc_respond_str(vc, "\033[0n"); @@ -947,13 +946,13 @@ static void vc_putchar(VCChardev *vc, int ch) break; case 's': /* save cursor position */ - s->x_saved = s->x; - s->y_saved = s->y; + vc->x_saved = s->x; + vc->y_saved = s->y; break; case 'u': /* restore cursor position */ - s->x = s->x_saved; - s->y = s->y_saved; + s->x = vc->x_saved; + s->y = vc->y_saved; break; default: trace_console_putchar_unhandled(ch); @@ -2427,17 +2426,17 @@ static void text_console_do_init(Chardev *chr) s->hw = s; /* set current text attributes to default */ - s->t_attrib = TEXT_ATTRIBUTES_DEFAULT; + drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT; text_console_resize(s); if (chr->label) { char *msg; - s->t_attrib.bgcol = QEMU_COLOR_BLUE; + 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); - s->t_attrib = TEXT_ATTRIBUTES_DEFAULT; + drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT; } qemu_chr_be_event(chr, CHR_EVENT_OPENED); -- cgit v1.1 From e265917c77710ef721e4c333bccfecf030c7776c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:51 +0400 Subject: ui/console: use OBJECT_DEFINE_TYPE for QemuConsole MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following patch will move some object initialization to the corresponding handlers. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-18-marcandre.lureau@redhat.com> --- ui/console.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 1336a1b..14fb38c 100644 --- a/ui/console.c +++ b/ui/console.c @@ -125,6 +125,8 @@ struct QemuConsole { QTAILQ_ENTRY(QemuConsole) next; }; +OBJECT_DEFINE_TYPE(QemuConsole, qemu_console, QEMU_CONSOLE, OBJECT) + struct VCChardev { Chardev parent; QemuConsole *console; @@ -1313,6 +1315,21 @@ static QemuConsole *new_console(console_type_t console_type, uint32_t head) return s; } +static void +qemu_console_finalize(Object *obj) +{ +} + +static void +qemu_console_class_init(ObjectClass *oc, void *data) +{ +} + +static void +qemu_console_init(Object *obj) +{ +} + #ifdef WIN32 void qemu_displaysurface_win32_set_handle(DisplaySurface *surface, HANDLE h, uint32_t offset) @@ -2646,13 +2663,6 @@ void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, Error **errp) } } -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); @@ -2678,10 +2688,3 @@ void qemu_console_early_init(void) type_register(&char_vc_type_info); } } - -static void register_types(void) -{ - type_register_static(&qemu_console_info); -} - -type_init(register_types); -- cgit v1.1 From 098d57e7c0aa347f08f0738e8bd55b9a7faed8d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:52 +0400 Subject: ui/console: change new_console() to use object initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Object construction should be done in respective object instance and class handlers. Introduce qemu_console_register() to split out the registration logic. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-19-marcandre.lureau@redhat.com> --- ui/console.c | 92 ++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 56 insertions(+), 36 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 14fb38c..bdecfe7 100644 --- a/ui/console.c +++ b/ui/console.c @@ -27,6 +27,7 @@ #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" @@ -1253,39 +1254,24 @@ static void text_console_update(void *opaque, console_ch_t *chardata) } } -static QemuConsole *new_console(console_type_t console_type, uint32_t head) +static void +qemu_console_register(QemuConsole *c, console_type_t console_type) { - 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; + (console_type == GRAPHIC_CONSOLE))) { + active_console = c; } - s->ds = ds; - s->console_type = console_type; - s->window_id = -1; + c->console_type = console_type; if (QTAILQ_EMPTY(&consoles)) { - s->index = 0; - QTAILQ_INSERT_TAIL(&consoles, s, next); + c->index = 0; + QTAILQ_INSERT_TAIL(&consoles, c, next); } else if (console_type != GRAPHIC_CONSOLE || 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. @@ -1293,41 +1279,75 @@ static QemuConsole *new_console(console_type_t console_type, uint32_t head) * 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 && + it->console_type == GRAPHIC_CONSOLE) { + it = QTAILQ_NEXT(it, next); } - if (c->console_type == GRAPHIC_CONSOLE) { + if (it->console_type == GRAPHIC_CONSOLE) { /* 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) { + /* TODO: should unregister from consoles and free itself */ +} + +static void +qemu_console_prop_get_head(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + QemuConsole *c = QEMU_CONSOLE(obj); + + visit_type_uint32(v, name, &c->head, errp); } static void qemu_console_class_init(ObjectClass *oc, void *data) { + object_class_property_add_link(oc, "device", TYPE_DEVICE, + offsetof(QemuConsole, device), + object_property_allow_set_link, + OBJ_PROP_LINK_STRONG); + object_class_property_add(oc, "head", "uint32", + qemu_console_prop_get_head, + NULL, NULL, NULL); } 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; +} + +static QemuConsole *new_console(console_type_t console_type, + uint32_t head) +{ + QemuConsole *c = QEMU_CONSOLE(object_new(TYPE_QEMU_CONSOLE)); + + c->head = head; + /* TODO: move to console_init() once there is a type hierarchy */ + qemu_console_register(c, console_type); + + return c; } #ifdef WIN32 -- cgit v1.1 From b208f745a8af27344c7c8401560b312a4f4bd539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:53 +0400 Subject: ui/console: introduce different console objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Boilerplate code to introduce different object types for the different console types. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-20-marcandre.lureau@redhat.com> --- ui/console.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index bdecfe7..4ca5064 100644 --- a/ui/console.c +++ b/ui/console.c @@ -128,6 +128,45 @@ struct QemuConsole { OBJECT_DEFINE_TYPE(QemuConsole, qemu_console, QEMU_CONSOLE, OBJECT) +typedef struct QemuGraphicConsole { + QemuConsole parent; +} QemuGraphicConsole; + +typedef QemuConsoleClass QemuGraphicConsoleClass; + +#define TYPE_QEMU_GRAPHIC_CONSOLE "qemu-graphic-console" +OBJECT_DECLARE_SIMPLE_TYPE(QemuGraphicConsole, QEMU_GRAPHIC_CONSOLE) +OBJECT_DEFINE_TYPE(QemuGraphicConsole, qemu_graphic_console, QEMU_GRAPHIC_CONSOLE, QEMU_CONSOLE) + +#define QEMU_IS_GRAPHIC_CONSOLE(c) \ + object_dynamic_cast(OBJECT(c), TYPE_QEMU_GRAPHIC_CONSOLE) + +typedef struct QemuTextConsole { + QemuConsole parent; +} QemuTextConsole; + +typedef QemuConsoleClass QemuTextConsoleClass; + +#define TYPE_QEMU_TEXT_CONSOLE "qemu-text-console" +OBJECT_DECLARE_SIMPLE_TYPE(QemuTextConsole, QEMU_TEXT_CONSOLE) +OBJECT_DEFINE_TYPE(QemuTextConsole, qemu_text_console, QEMU_TEXT_CONSOLE, QEMU_CONSOLE) + +#define QEMU_IS_TEXT_CONSOLE(c) \ + object_dynamic_cast(OBJECT(c), TYPE_QEMU_TEXT_CONSOLE) + +typedef struct QemuFixedTextConsole { + QemuTextConsole parent; +} QemuFixedTextConsole; + +typedef QemuTextConsoleClass QemuFixedTextConsoleClass; + +#define TYPE_QEMU_FIXED_TEXT_CONSOLE "qemu-fixed-text-console" +OBJECT_DECLARE_SIMPLE_TYPE(QemuFixedTextConsole, QEMU_FIXED_TEXT_CONSOLE) +OBJECT_DEFINE_TYPE(QemuFixedTextConsole, qemu_fixed_text_console, QEMU_FIXED_TEXT_CONSOLE, QEMU_TEXT_CONSOLE) + +#define QEMU_IS_FIXED_TEXT_CONSOLE(c) \ + object_dynamic_cast(OBJECT(c), TYPE_QEMU_FIXED_TEXT_CONSOLE) + struct VCChardev { Chardev parent; QemuConsole *console; @@ -1338,6 +1377,51 @@ qemu_console_init(Object *obj) c->window_id = -1; } +static void +qemu_graphic_console_finalize(Object *obj) +{ +} + +static void +qemu_graphic_console_class_init(ObjectClass *oc, void *data) +{ +} + +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) +{ +} + +static void +qemu_text_console_init(Object *obj) +{ +} + +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) +{ +} + static QemuConsole *new_console(console_type_t console_type, uint32_t head) { -- cgit v1.1 From c105d60f7fe912cca558ce5ff5680bfd0c1300fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:54 +0400 Subject: ui/console: instantiate a specific console type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will allow to move code/data to the specific console types. Replace console_type_t with object type check. QemuConsole can be abstract. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-21-marcandre.lureau@redhat.com> --- ui/console.c | 47 +++++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 28 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 4ca5064..dd8e8db 100644 --- a/ui/console.c +++ b/ui/console.c @@ -71,17 +71,10 @@ enum TTYState { 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; @@ -126,7 +119,7 @@ struct QemuConsole { QTAILQ_ENTRY(QemuConsole) next; }; -OBJECT_DEFINE_TYPE(QemuConsole, qemu_console, QEMU_CONSOLE, OBJECT) +OBJECT_DEFINE_ABSTRACT_TYPE(QemuConsole, qemu_console, QEMU_CONSOLE, OBJECT) typedef struct QemuGraphicConsole { QemuConsole parent; @@ -1156,7 +1149,7 @@ void kbd_put_keysym_console(QemuConsole *s, int keysym) int c; uint32_t num_free; - if (!s || (s->console_type == GRAPHIC_CONSOLE)) + if (!s || QEMU_IS_GRAPHIC_CONSOLE(s)) return; switch(keysym) { @@ -1258,7 +1251,7 @@ static void text_console_invalidate(void *opaque) { QemuConsole *s = (QemuConsole *) opaque; - if (s->console_type == TEXT_CONSOLE) { + if (QEMU_IS_TEXT_CONSOLE(s) && !QEMU_IS_FIXED_TEXT_CONSOLE(s)) { text_console_resize(s); } console_refresh(s); @@ -1294,20 +1287,19 @@ static void text_console_update(void *opaque, console_ch_t *chardata) } static void -qemu_console_register(QemuConsole *c, console_type_t console_type) +qemu_console_register(QemuConsole *c) { int i; - if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) && - (console_type == GRAPHIC_CONSOLE))) { + if (!active_console || (!QEMU_IS_GRAPHIC_CONSOLE(active_console) && + QEMU_IS_GRAPHIC_CONSOLE(c))) { active_console = c; } - c->console_type = console_type; if (QTAILQ_EMPTY(&consoles)) { c->index = 0; QTAILQ_INSERT_TAIL(&consoles, c, next); - } else if (console_type != GRAPHIC_CONSOLE || phase_check(PHASE_MACHINE_READY)) { + } else if (!QEMU_IS_GRAPHIC_CONSOLE(c) || phase_check(PHASE_MACHINE_READY)) { QemuConsole *last = QTAILQ_LAST(&consoles); c->index = last->index + 1; QTAILQ_INSERT_TAIL(&consoles, c, next); @@ -1320,11 +1312,10 @@ qemu_console_register(QemuConsole *c, console_type_t console_type) */ QemuConsole *it = QTAILQ_FIRST(&consoles); - while (QTAILQ_NEXT(it, next) != NULL && - it->console_type == GRAPHIC_CONSOLE) { + while (QTAILQ_NEXT(it, next) != NULL && QEMU_IS_GRAPHIC_CONSOLE(it)) { it = QTAILQ_NEXT(it, next); } - if (it->console_type == GRAPHIC_CONSOLE) { + if (QEMU_IS_GRAPHIC_CONSOLE(it)) { /* have no text consoles */ c->index = it->index + 1; QTAILQ_INSERT_AFTER(&consoles, it, c, next); @@ -1422,14 +1413,14 @@ qemu_fixed_text_console_init(Object *obj) { } -static QemuConsole *new_console(console_type_t console_type, +static QemuConsole *new_console(const char *typename, uint32_t head) { - QemuConsole *c = QEMU_CONSOLE(object_new(TYPE_QEMU_CONSOLE)); + QemuConsole *c = QEMU_CONSOLE(object_new(typename)); c->head = head; /* TODO: move to console_init() once there is a type hierarchy */ - qemu_console_register(c, console_type); + qemu_console_register(c); return c; } @@ -2211,7 +2202,7 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head, height = qemu_console_get_height(s, 0); } else { trace_console_gfx_new(); - s = new_console(GRAPHIC_CONSOLE, head); + s = new_console(TYPE_QEMU_GRAPHIC_CONSOLE, head); s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, dpy_set_ui_info_timer, s); } @@ -2345,7 +2336,7 @@ bool qemu_console_is_graphic(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) @@ -2353,7 +2344,7 @@ 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) @@ -2389,7 +2380,7 @@ bool qemu_console_is_multihead(DeviceState *dev) char *qemu_console_get_label(QemuConsole *con) { - if (con->console_type == GRAPHIC_CONSOLE) { + if (QEMU_IS_GRAPHIC_CONSOLE(con)) { if (con->device) { DeviceState *dev; bool multihead; @@ -2588,9 +2579,9 @@ static void vc_chr_open(Chardev *chr, trace_console_txt_new(width, height); if (width == 0 || height == 0) { - s = new_console(TEXT_CONSOLE, 0); + s = new_console(TYPE_QEMU_TEXT_CONSOLE, 0); } else { - s = new_console(TEXT_CONSOLE_FIXED_SIZE, 0); + s = new_console(TYPE_QEMU_FIXED_TEXT_CONSOLE, 0); s->scanout.kind = SCANOUT_SURFACE; s->surface = qemu_create_displaysurface(width, height); } @@ -2610,7 +2601,7 @@ 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)) && -- cgit v1.1 From ba0ec5c2931cd6efafc92bde3bd8fc3f99594fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:55 +0400 Subject: ui/console: register the console from qemu_console_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-22-marcandre.lureau@redhat.com> --- ui/console.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index dd8e8db..02a24ea 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1366,6 +1366,7 @@ qemu_console_init(Object *obj) qemu_co_queue_init(&c->dump_queue); c->ds = ds; c->window_id = -1; + qemu_console_register(c); } static void @@ -1419,8 +1420,6 @@ static QemuConsole *new_console(const char *typename, QemuConsole *c = QEMU_CONSOLE(object_new(typename)); c->head = head; - /* TODO: move to console_init() once there is a type hierarchy */ - qemu_console_register(c); return c; } -- cgit v1.1 From 34b7751574ebac7e19bfdb3ed0f91550c5ed171b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:56 +0400 Subject: ui/console: remove new_console() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The constructor helper isn't of much used now. "head" is only specified for graphic console (and default to 0), and we are going to move it to QemuGraphicConsole next. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-23-marcandre.lureau@redhat.com> --- ui/console.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 02a24ea..e0e4f98 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1414,16 +1414,6 @@ qemu_fixed_text_console_init(Object *obj) { } -static QemuConsole *new_console(const char *typename, - uint32_t head) -{ - QemuConsole *c = QEMU_CONSOLE(object_new(typename)); - - c->head = head; - - return c; -} - #ifdef WIN32 void qemu_displaysurface_win32_set_handle(DisplaySurface *surface, HANDLE h, uint32_t offset) @@ -2163,7 +2153,7 @@ DisplayState *init_displaystate(void) 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); @@ -2201,7 +2191,8 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head, height = qemu_console_get_height(s, 0); } else { trace_console_gfx_new(); - s = new_console(TYPE_QEMU_GRAPHIC_CONSOLE, head); + s = (QemuConsole *)object_new(TYPE_QEMU_GRAPHIC_CONSOLE); + s->head = head; s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, dpy_set_ui_info_timer, s); } @@ -2578,9 +2569,9 @@ static void vc_chr_open(Chardev *chr, trace_console_txt_new(width, height); if (width == 0 || height == 0) { - s = new_console(TYPE_QEMU_TEXT_CONSOLE, 0); + s = (QemuConsole *)object_new(TYPE_QEMU_TEXT_CONSOLE); } else { - s = new_console(TYPE_QEMU_FIXED_TEXT_CONSOLE, 0); + s = (QemuConsole *)object_new(TYPE_QEMU_FIXED_TEXT_CONSOLE); s->scanout.kind = SCANOUT_SURFACE; s->surface = qemu_create_displaysurface(width, height); } -- cgit v1.1 From f9411aaebd99e1efb04f0d32f01b37467e43b6a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:57 +0400 Subject: ui/console: specialize console_lookup_unused() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit graphics_console_init() is expected to return a graphic console. The function doesn't need to be exported. We are going to specialize further QemuGraphicConsole & QemuTextConsole. The two will not be interchangeable anymore. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-24-marcandre.lureau@redhat.com> --- ui/console.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index e0e4f98..08bed58 100644 --- a/ui/console.c +++ b/ui/console.c @@ -196,6 +196,7 @@ static void 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 gui_update(void *opaque) { @@ -2184,7 +2185,7 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head, 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); @@ -2289,13 +2290,13 @@ QemuConsole *qemu_console_lookup_by_device_name(const char *device_id, 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), -- cgit v1.1 From 7fa4b8041b870951642515e0954d274ec4d599b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:58 +0400 Subject: ui/console: update the head from unused QemuConsole MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When recycling unused QemuConsole, we should still set the associated head number for correct information and lookups. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-25-marcandre.lureau@redhat.com> --- ui/console.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 08bed58..a9a922b 100644 --- a/ui/console.c +++ b/ui/console.c @@ -2193,10 +2193,10 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head, } else { trace_console_gfx_new(); s = (QemuConsole *)object_new(TYPE_QEMU_GRAPHIC_CONSOLE); - s->head = head; s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, dpy_set_ui_info_timer, s); } + s->head = head; graphic_console_set_hwops(s, hw_ops, opaque); if (dev) { object_property_set_link(OBJECT(s), "device", OBJECT(dev), -- cgit v1.1 From cfde05d15bbad620f87592edc2882611acbacc53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:37:59 +0400 Subject: ui/console: allocate ui_timer in QemuConsole MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Although at this point only QemuGraphicConsole have hw_ops that implements ui_info() callback, it makes sense to keep the code in the base QemuConsole, to simplify conditions for the caller. As of now, the code didn't reach a NULL timer because dpy_set_ui_info() checks if dpy_ui_info_supported() (hw_ops->ui_info != NULL), which is false for text_console_ops. This is a bit fragile, let simply allocate and free the timer in the base class. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-26-marcandre.lureau@redhat.com> --- ui/console.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index a9a922b..8c4a2c8 100644 --- a/ui/console.c +++ b/ui/console.c @@ -197,6 +197,7 @@ 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) { @@ -1334,6 +1335,9 @@ qemu_console_register(QemuConsole *c) static void qemu_console_finalize(Object *obj) { + QemuConsole *c = QEMU_CONSOLE(obj); + + g_clear_pointer(&c->ui_timer, timer_free); /* TODO: should unregister from consoles and free itself */ } @@ -1367,6 +1371,8 @@ qemu_console_init(Object *obj) 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); } @@ -2193,8 +2199,6 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head, } else { trace_console_gfx_new(); s = (QemuConsole *)object_new(TYPE_QEMU_GRAPHIC_CONSOLE); - s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, - dpy_set_ui_info_timer, s); } s->head = head; graphic_console_set_hwops(s, hw_ops, opaque); -- cgit v1.1 From b97a76d0355f8fc3856de9ebd4f6929b51ba26fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:38:00 +0400 Subject: ui/vc: move cursor_timer initialization to QemuTextConsole class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The timer is only relevant when a text console exists. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-27-marcandre.lureau@redhat.com> --- ui/console.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 8c4a2c8..ffa68c3 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1399,6 +1399,10 @@ 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, + text_console_update_cursor, NULL); + } } static void @@ -2144,8 +2148,6 @@ static DisplayState *get_alloc_displaystate(void) { 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; } -- cgit v1.1 From 463c6b19c75313734e6e1b624d6b89dd8eb62516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:38:01 +0400 Subject: ui/console: free more QemuConsole resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This code path is probably not executed at this point, since console aren't being released. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-28-marcandre.lureau@redhat.com> --- ui/console.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index ffa68c3..3cd4c74 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1337,8 +1337,11 @@ qemu_console_finalize(Object *obj) { QemuConsole *c = QEMU_CONSOLE(obj); + /* TODO: check this code path, and unregister from consoles */ + g_clear_pointer(&c->device, object_unref); + 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); - /* TODO: should unregister from consoles and free itself */ } static void -- cgit v1.1 From b2bb9cc43dbb942a5333a6271629fd6094771bca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:38:02 +0400 Subject: ui/vc: move text fields to QemuTextConsole MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now we can instantiate the specific console with its own fields. Pass the most appropriate type to the various functions, and cast up to QEMU_CONSOLE as necessary. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-29-marcandre.lureau@redhat.com> --- ui/console.c | 177 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 91 insertions(+), 86 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 3cd4c74..335d7ba 100644 --- a/ui/console.c +++ b/ui/console.c @@ -94,26 +94,6 @@ struct QemuConsole { const GraphicHwOps *hw_ops; void *hw; - /* Text console state */ - int width; - int height; - int total_height; - int backscroll_height; - int x, y; - int y_displayed; - int y_base; - TextCell *cells; - int text_x[2], text_y[2], cursor_invalidate; - int echo; - - int update_x0; - int update_y0; - int update_x1; - int update_y1; - - Chardev *chr; - /* fifo for key pressed */ - Fifo8 out_fifo; CoQueue dump_queue; QTAILQ_ENTRY(QemuConsole) next; @@ -136,6 +116,26 @@ OBJECT_DEFINE_TYPE(QemuGraphicConsole, qemu_graphic_console, QEMU_GRAPHIC_CONSOL typedef struct QemuTextConsole { QemuConsole parent; + + int width; + int height; + int total_height; + int backscroll_height; + int x, y; + int y_displayed; + int y_base; + TextCell *cells; + int text_x[2], text_y[2], cursor_invalidate; + int echo; + + int update_x0; + int update_y0; + int update_x1; + int update_y1; + + Chardev *chr; + /* fifo for key pressed */ + Fifo8 out_fifo; } QemuTextConsole; typedef QemuConsoleClass QemuTextConsoleClass; @@ -162,7 +162,7 @@ OBJECT_DEFINE_TYPE(QemuFixedTextConsole, qemu_fixed_text_console, QEMU_FIXED_TEX struct VCChardev { Chardev parent; - QemuConsole *console; + QemuTextConsole *console; enum TTYState state; int esc_params[MAX_ESC_PARAMS]; @@ -428,43 +428,44 @@ static void vga_putcharxy(QemuConsole *s, int x, int y, int ch, &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; 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; + last_width = t->width; + t->width = surface_width(s->surface) / FONT_WIDTH; + t->height = surface_height(s->surface) / FONT_HEIGHT; w1 = last_width; - if (s->width < w1) - w1 = s->width; + if (t->width < w1) + w1 = t->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]; + 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) @@ -479,7 +480,7 @@ static void invalidate_xy(QemuConsole *s, int x, int y) static void vc_update_xy(VCChardev *vc, int x, int y) { - QemuConsole *s = vc->console; + QemuTextConsole *s = vc->console; TextCell *c; int y1, y2; @@ -498,13 +499,13 @@ static void vc_update_xy(VCChardev *vc, int x, int y) 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; @@ -525,17 +526,17 @@ static void console_show_cursor(QemuConsole *s, int show) 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; @@ -545,13 +546,13 @@ static void console_refresh(QemuConsole *s) s->text_y[1] = s->height - 1; s->cursor_invalidate = 1; - vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface), + vga_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++; } @@ -560,11 +561,11 @@ static void console_refresh(QemuConsole *s) } } 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; @@ -595,7 +596,7 @@ static void console_scroll(QemuConsole *s, int ydelta) static void vc_put_lf(VCChardev *vc) { - QemuConsole *s = vc->console; + QemuTextConsole *s = vc->console; TextCell *c; int x, y1; @@ -624,10 +625,10 @@ static void vc_put_lf(VCChardev *vc) s->text_x[1] = s->width - 1; s->text_y[1] = s->height - 1; - vga_bitblt(s, 0, FONT_HEIGHT, 0, 0, + vga_bitblt(QEMU_CONSOLE(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, + vga_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; @@ -737,7 +738,7 @@ static void vc_handle_escape(VCChardev *vc) 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; @@ -750,7 +751,7 @@ static void vc_clear_xy(VCChardev *vc, int x, int y) 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) { @@ -777,7 +778,7 @@ static void vc_respond_str(VCChardev *vc, const char *buf) /* 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; @@ -798,7 +799,7 @@ static void vc_set_cursor(VCChardev *vc, int x, int y) static void vc_putchar(VCChardev *vc, int ch) { - QemuConsole *s = vc->console; + QemuTextConsole *s = vc->console; int i; int x, y; char response[40]; @@ -1095,8 +1096,11 @@ void console_select(unsigned int index) } 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)) { + dpy_text_resize(s, QEMU_TEXT_CONSOLE(s)->width, QEMU_TEXT_CONSOLE(s)->height); + text_console_update_cursor(NULL); + } } } @@ -1107,7 +1111,7 @@ DECLARE_INSTANCE_CHECKER(VCChardev, VC_CHARDEV, 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; @@ -1120,14 +1124,14 @@ static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len) } 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; @@ -1145,13 +1149,14 @@ static void kbd_send_chars(QemuConsole *s) } /* called when an ascii key is pressed */ -void kbd_put_keysym_console(QemuConsole *s, int keysym) +void kbd_put_keysym_console(QemuConsole *con, int keysym) { + QemuTextConsole *s = (QemuTextConsole *)object_dynamic_cast(OBJECT(con), TYPE_QEMU_TEXT_CONSOLE); uint8_t buf[16], *q; int c; uint32_t num_free; - if (!s || QEMU_IS_GRAPHIC_CONSOLE(s)) + if (!s) return; switch(keysym) { @@ -1251,17 +1256,17 @@ void kbd_put_keysym(int keysym) static void text_console_invalidate(void *opaque) { - QemuConsole *s = (QemuConsole *) opaque; + QemuTextConsole *s = QEMU_TEXT_CONSOLE(opaque); - if (QEMU_IS_TEXT_CONSOLE(s) && !QEMU_IS_FIXED_TEXT_CONSOLE(s)) { - 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]) { @@ -1275,7 +1280,7 @@ static void text_console_update(void *opaque, console_ch_t *chardata) 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; @@ -1283,7 +1288,7 @@ static void text_console_update(void *opaque, console_ch_t *chardata) 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; } } @@ -2399,12 +2404,14 @@ char *qemu_console_get_label(QemuConsole *con) } } return g_strdup("VGA"); - } else { - if (con->chr && con->chr->label) { - return g_strdup(con->chr->label); + } else if (QEMU_IS_TEXT_CONSOLE(con)) { + QemuTextConsole *c = QEMU_TEXT_CONSOLE(con); + if (c->chr && c->chr->label) { + return g_strdup(c->chr->label); } - return g_strdup_printf("vc%d", con->index); } + + return g_strdup_printf("vc%d", con->index); } int qemu_console_get_index(QemuConsole *con) @@ -2466,17 +2473,15 @@ int qemu_console_get_height(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; + drv->console->echo = echo; } static void text_console_update_cursor_timer(void) @@ -2514,7 +2519,7 @@ static const GraphicHwOps text_console_ops = { static void text_console_do_init(Chardev *chr) { VCChardev *drv = VC_CHARDEV(chr); - QemuConsole *s = drv->console; + QemuTextConsole *s = drv->console; int g_width = 80 * FONT_WIDTH; int g_height = 24 * FONT_HEIGHT; @@ -2525,17 +2530,17 @@ static void text_console_do_init(Chardev *chr) s->total_height = DEFAULT_BACKSCROLL; s->x = 0; s->y = 0; - if (s->scanout.kind != SCANOUT_SURFACE) { + if (QEMU_CONSOLE(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; + QEMU_CONSOLE(s)->surface = qemu_create_displaysurface(g_width, g_height); + QEMU_CONSOLE(s)->scanout.kind = SCANOUT_SURFACE; } - s->hw_ops = &text_console_ops; - s->hw = s; + QEMU_CONSOLE(s)->hw_ops = &text_console_ops; + QEMU_CONSOLE(s)->hw = s; /* set current text attributes to default */ drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT; @@ -2561,7 +2566,7 @@ 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; @@ -2579,11 +2584,11 @@ static void vc_chr_open(Chardev *chr, trace_console_txt_new(width, height); if (width == 0 || height == 0) { - s = (QemuConsole *)object_new(TYPE_QEMU_TEXT_CONSOLE); + s = QEMU_TEXT_CONSOLE(object_new(TYPE_QEMU_TEXT_CONSOLE)); } else { - s = (QemuConsole *)object_new(TYPE_QEMU_FIXED_TEXT_CONSOLE); - s->scanout.kind = SCANOUT_SURFACE; - s->surface = qemu_create_displaysurface(width, height); + s = QEMU_TEXT_CONSOLE(object_new(TYPE_QEMU_FIXED_TEXT_CONSOLE)); + QEMU_CONSOLE(s)->scanout.kind = SCANOUT_SURFACE; + QEMU_CONSOLE(s)->surface = qemu_create_displaysurface(width, height); } s->chr = chr; -- cgit v1.1 From 58d5870845c61cea1e7df287b86c2607b2bf48a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:38:03 +0400 Subject: ui/console: move graphic fields to QemuGraphicConsole MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move fields specific to graphic console to the console subclass. qemu_console_get_head() is adapated to accomodate QemuTextConsole, and always returns 0. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-30-marcandre.lureau@redhat.com> --- ui/console.c | 110 ++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 64 insertions(+), 46 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 335d7ba..9d884ba 100644 --- a/ui/console.c +++ b/ui/console.c @@ -83,17 +83,10 @@ struct QemuConsole { int gl_block; QEMUTimer *gl_unblock_timer; int window_id; - - /* 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; - CoQueue dump_queue; QTAILQ_ENTRY(QemuConsole) next; @@ -103,6 +96,12 @@ OBJECT_DEFINE_ABSTRACT_TYPE(QemuConsole, qemu_console, QEMU_CONSOLE, OBJECT) typedef struct QemuGraphicConsole { QemuConsole parent; + + Object *device; + uint32_t head; + + QEMUCursor *cursor; + int cursor_x, cursor_y, cursor_on; } QemuGraphicConsole; typedef QemuConsoleClass QemuGraphicConsoleClass; @@ -1343,31 +1342,14 @@ qemu_console_finalize(Object *obj) QemuConsole *c = QEMU_CONSOLE(obj); /* TODO: check this code path, and unregister from consoles */ - g_clear_pointer(&c->device, object_unref); 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_prop_get_head(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - QemuConsole *c = QEMU_CONSOLE(obj); - - visit_type_uint32(v, name, &c->head, errp); -} - -static void qemu_console_class_init(ObjectClass *oc, void *data) { - object_class_property_add_link(oc, "device", TYPE_DEVICE, - offsetof(QemuConsole, device), - object_property_allow_set_link, - OBJ_PROP_LINK_STRONG); - object_class_property_add(oc, "head", "uint32", - qemu_console_prop_get_head, - NULL, NULL, NULL); } static void @@ -1387,11 +1369,30 @@ qemu_console_init(Object *obj) 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 @@ -1676,6 +1677,16 @@ void qemu_console_set_display_gl_ctx(QemuConsole *con, DisplayGLCtx *gl) 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; @@ -1693,11 +1704,8 @@ void register_displaychangelistener(DisplayChangeListener *dcl) 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 (con && dcl->ops->dpy_mouse_set) { - dcl->ops->dpy_mouse_set(dcl, con->cursor_x, con->cursor_y, con->cursor_on); + if (QEMU_IS_GRAPHIC_CONSOLE(con)) { + dcl_set_graphic_cursor(dcl, QEMU_GRAPHIC_CONSOLE(con)); } text_console_update_cursor(NULL); } @@ -1728,8 +1736,9 @@ void unregister_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) @@ -1939,19 +1948,20 @@ void dpy_text_resize(QemuConsole *con, int w, int h) } } -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) { @@ -1960,18 +1970,19 @@ void dpy_mouse_set(QemuConsole *con, int x, int y, int on) } } -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) { @@ -2210,7 +2221,7 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head, trace_console_gfx_new(); s = (QemuConsole *)object_new(TYPE_QEMU_GRAPHIC_CONSOLE); } - s->head = head; + 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), @@ -2328,7 +2339,7 @@ QEMUCursor *qemu_console_get_cursor(QemuConsole *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) @@ -2386,21 +2397,22 @@ bool qemu_console_is_multihead(DeviceState *dev) char *qemu_console_get_label(QemuConsole *con) { if (QEMU_IS_GRAPHIC_CONSOLE(con)) { - if (con->device) { + 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"); @@ -2427,7 +2439,13 @@ uint32_t qemu_console_get_head(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) -- cgit v1.1 From 98ee9dab81b2bc75d6ccf86681053ed80f9fc9af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:38:04 +0400 Subject: ui/vc: fold text_console_do_init() in vc_chr_open() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Message-Id: <20230830093843.3531473-31-marcandre.lureau@redhat.com> --- ui/console.c | 80 +++++++++++++++++++++++------------------------------------- 1 file changed, 31 insertions(+), 49 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 9d884ba..22505d0 100644 --- a/ui/console.c +++ b/ui/console.c @@ -187,7 +187,6 @@ static QTAILQ_HEAD(, QemuConsole) consoles = 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); @@ -2534,49 +2533,6 @@ static const GraphicHwOps text_console_ops = { .text_update = text_console_update, }; -static void text_console_do_init(Chardev *chr) -{ - VCChardev *drv = VC_CHARDEV(chr); - QemuTextConsole *s = drv->console; - int g_width = 80 * FONT_WIDTH; - int g_height = 24 * FONT_HEIGHT; - - fifo8_create(&s->out_fifo, 16); - - s->y_displayed = 0; - s->y_base = 0; - s->total_height = DEFAULT_BACKSCROLL; - s->x = 0; - s->y = 0; - if (QEMU_CONSOLE(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); - } - QEMU_CONSOLE(s)->surface = qemu_create_displaysurface(g_width, g_height); - QEMU_CONSOLE(s)->scanout.kind = SCANOUT_SURFACE; - } - - QEMU_CONSOLE(s)->hw_ops = &text_console_ops; - QEMU_CONSOLE(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, ChardevBackend *backend, bool *be_opened, @@ -2587,6 +2543,8 @@ static void vc_chr_open(Chardev *chr, QemuTextConsole *s; unsigned width = 0; unsigned height = 0; + int g_width = 80 * FONT_WIDTH; + int g_height = 24 * FONT_HEIGHT; if (vc->has_width) { width = vc->width; @@ -2612,12 +2570,36 @@ static void vc_chr_open(Chardev *chr, s->chr = chr; drv->console = s; - text_console_do_init(chr); + fifo8_create(&s->out_fifo, 16); - /* console/chardev init sometimes completes elsewhere in a 2nd - * stage, so defer OPENED events until they are fully initialized - */ - *be_opened = false; + s->total_height = DEFAULT_BACKSCROLL; + if (QEMU_CONSOLE(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); + } + QEMU_CONSOLE(s)->surface = qemu_create_displaysurface(g_width, g_height); + QEMU_CONSOLE(s)->scanout.kind = SCANOUT_SURFACE; + } + + QEMU_CONSOLE(s)->hw_ops = &text_console_ops; + QEMU_CONSOLE(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; + } + + *be_opened = true; } void qemu_console_resize(QemuConsole *s, int width, int height) -- cgit v1.1 From 60cb14b4f9d94d750640f42e0f18a1710b8d6c1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:38:05 +0400 Subject: ui/vc: move some text console initialization to qom handlers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-32-marcandre.lureau@redhat.com> --- ui/console.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 22505d0..5d521ba 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1413,9 +1413,20 @@ qemu_text_console_class_init(ObjectClass *oc, void *data) } } +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 @@ -2528,11 +2539,6 @@ static void text_console_update_cursor(void *opaque) } } -static const GraphicHwOps text_console_ops = { - .invalidate = text_console_invalidate, - .text_update = text_console_update, -}; - static void vc_chr_open(Chardev *chr, ChardevBackend *backend, bool *be_opened, @@ -2570,9 +2576,6 @@ static void vc_chr_open(Chardev *chr, s->chr = chr; drv->console = s; - fifo8_create(&s->out_fifo, 16); - - s->total_height = DEFAULT_BACKSCROLL; if (QEMU_CONSOLE(s)->scanout.kind != SCANOUT_SURFACE) { if (active_console && active_console->scanout.kind == SCANOUT_SURFACE) { g_width = qemu_console_get_width(active_console, g_width); @@ -2582,9 +2585,6 @@ static void vc_chr_open(Chardev *chr, QEMU_CONSOLE(s)->scanout.kind = SCANOUT_SURFACE; } - QEMU_CONSOLE(s)->hw_ops = &text_console_ops; - QEMU_CONSOLE(s)->hw = s; - /* set current text attributes to default */ drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT; text_console_resize(s); -- cgit v1.1 From 5e5a30b7d17f207a85af167ba3efdeff2b1f61de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:38:06 +0400 Subject: ui/console: simplify getting active_console size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can get the active console dimension regardless of its kind, by simply giving NULL as argument. It will fallback with the given value when the dimensions aren't known. This will also allow to move the code in a separate unit more easily. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-33-marcandre.lureau@redhat.com> --- ui/console.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 5d521ba..70e11f9 100644 --- a/ui/console.c +++ b/ui/console.c @@ -2577,10 +2577,8 @@ static void vc_chr_open(Chardev *chr, drv->console = s; if (QEMU_CONSOLE(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); - } + g_width = qemu_console_get_width(NULL, g_width); + g_height = qemu_console_get_height(NULL, g_height); QEMU_CONSOLE(s)->surface = qemu_create_displaysurface(g_width, g_height); QEMU_CONSOLE(s)->scanout.kind = SCANOUT_SURFACE; } -- cgit v1.1 From 6ce7b1fa8844db668f0a3c0b37b78b08d331a16a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:38:07 +0400 Subject: ui/console: remove need for g_width/g_height MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-34-marcandre.lureau@redhat.com> --- ui/console.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 70e11f9..a3fd1c5 100644 --- a/ui/console.c +++ b/ui/console.c @@ -2549,8 +2549,6 @@ static void vc_chr_open(Chardev *chr, QemuTextConsole *s; unsigned width = 0; unsigned height = 0; - int g_width = 80 * FONT_WIDTH; - int g_height = 24 * FONT_HEIGHT; if (vc->has_width) { width = vc->width; @@ -2567,6 +2565,8 @@ static void vc_chr_open(Chardev *chr, trace_console_txt_new(width, height); if (width == 0 || height == 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 = QEMU_TEXT_CONSOLE(object_new(TYPE_QEMU_FIXED_TEXT_CONSOLE)); QEMU_CONSOLE(s)->scanout.kind = SCANOUT_SURFACE; @@ -2577,9 +2577,7 @@ static void vc_chr_open(Chardev *chr, drv->console = s; if (QEMU_CONSOLE(s)->scanout.kind != SCANOUT_SURFACE) { - g_width = qemu_console_get_width(NULL, g_width); - g_height = qemu_console_get_height(NULL, g_height); - QEMU_CONSOLE(s)->surface = qemu_create_displaysurface(g_width, g_height); + QEMU_CONSOLE(s)->surface = qemu_create_displaysurface(width, height); QEMU_CONSOLE(s)->scanout.kind = SCANOUT_SURFACE; } -- cgit v1.1 From 742a6896ea1b83894e68b2dc455b63cea498bafc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:38:08 +0400 Subject: ui/vc: use common text console surface creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-35-marcandre.lureau@redhat.com> --- ui/console.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index a3fd1c5..3d88495 100644 --- a/ui/console.c +++ b/ui/console.c @@ -2569,18 +2569,13 @@ static void vc_chr_open(Chardev *chr, height = qemu_console_get_height(NULL, 24 * FONT_HEIGHT); } else { s = QEMU_TEXT_CONSOLE(object_new(TYPE_QEMU_FIXED_TEXT_CONSOLE)); - QEMU_CONSOLE(s)->scanout.kind = SCANOUT_SURFACE; - QEMU_CONSOLE(s)->surface = qemu_create_displaysurface(width, height); } + dpy_gfx_replace_surface(QEMU_CONSOLE(s), qemu_create_displaysurface(width, height)); + s->chr = chr; drv->console = s; - if (QEMU_CONSOLE(s)->scanout.kind != SCANOUT_SURFACE) { - QEMU_CONSOLE(s)->surface = qemu_create_displaysurface(width, height); - QEMU_CONSOLE(s)->scanout.kind = SCANOUT_SURFACE; - } - /* set current text attributes to default */ drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT; text_console_resize(s); -- cgit v1.1 From 8c6381d84668ff9b6324bf00b91107cbcaf7505f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:38:09 +0400 Subject: ui/console: declare console types in console.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are going to split the console.c unit next, and implement separately. But we need to check the underlying type in various places. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-36-marcandre.lureau@redhat.com> --- ui/console.c | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 3d88495..ed9e713 100644 --- a/ui/console.c +++ b/ui/console.c @@ -106,13 +106,8 @@ typedef struct QemuGraphicConsole { typedef QemuConsoleClass QemuGraphicConsoleClass; -#define TYPE_QEMU_GRAPHIC_CONSOLE "qemu-graphic-console" -OBJECT_DECLARE_SIMPLE_TYPE(QemuGraphicConsole, QEMU_GRAPHIC_CONSOLE) OBJECT_DEFINE_TYPE(QemuGraphicConsole, qemu_graphic_console, QEMU_GRAPHIC_CONSOLE, QEMU_CONSOLE) -#define QEMU_IS_GRAPHIC_CONSOLE(c) \ - object_dynamic_cast(OBJECT(c), TYPE_QEMU_GRAPHIC_CONSOLE) - typedef struct QemuTextConsole { QemuConsole parent; @@ -139,26 +134,16 @@ typedef struct QemuTextConsole { typedef QemuConsoleClass QemuTextConsoleClass; -#define TYPE_QEMU_TEXT_CONSOLE "qemu-text-console" -OBJECT_DECLARE_SIMPLE_TYPE(QemuTextConsole, QEMU_TEXT_CONSOLE) OBJECT_DEFINE_TYPE(QemuTextConsole, qemu_text_console, QEMU_TEXT_CONSOLE, QEMU_CONSOLE) -#define QEMU_IS_TEXT_CONSOLE(c) \ - object_dynamic_cast(OBJECT(c), TYPE_QEMU_TEXT_CONSOLE) - typedef struct QemuFixedTextConsole { QemuTextConsole parent; } QemuFixedTextConsole; typedef QemuTextConsoleClass QemuFixedTextConsoleClass; -#define TYPE_QEMU_FIXED_TEXT_CONSOLE "qemu-fixed-text-console" -OBJECT_DECLARE_SIMPLE_TYPE(QemuFixedTextConsole, QEMU_FIXED_TEXT_CONSOLE) OBJECT_DEFINE_TYPE(QemuFixedTextConsole, qemu_fixed_text_console, QEMU_FIXED_TEXT_CONSOLE, QEMU_TEXT_CONSOLE) -#define QEMU_IS_FIXED_TEXT_CONSOLE(c) \ - object_dynamic_cast(OBJECT(c), TYPE_QEMU_FIXED_TEXT_CONSOLE) - struct VCChardev { Chardev parent; QemuTextConsole *console; -- cgit v1.1 From 1ece6777fe1770f8a26f6887be96b21edfd0e442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:38:10 +0400 Subject: ui/console: use QEMU_PIXMAN_COLOR helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU_RGB macro is actually defining a pixman color. Make this explicit in the macro name. Move it to qemu-pixman.h so it can be used elsewhere, as done in the following patch. Finally, define QEMU_PIXMAN_COLOR_{BLACK,GRAY}, to avoid need to look up the VGA color table from the QemuConsole placeholder surface rendering. Signed-off-by: Marc-André Lureau Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230830093843.3531473-37-marcandre.lureau@redhat.com> --- ui/console.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index ed9e713..88e37ea 100644 --- a/ui/console.c +++ b/ui/console.c @@ -363,29 +363,26 @@ static void vga_bitblt(QemuConsole *con, #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 */ } }; @@ -1520,8 +1517,8 @@ DisplaySurface *qemu_create_placeholder_surface(int w, int h, 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; -- cgit v1.1 From b704a8ce0c17f2f9f50a62cbe9053ef587c35db4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:38:11 +0400 Subject: ui/console: rename vga_ functions with qemu_console_ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They are not specific to VGA. Let's use the object type name as prefix instead, to avoid confusion. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230830093843.3531473-38-marcandre.lureau@redhat.com> --- ui/console.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 88e37ea..a157a5b 100644 --- a/ui/console.c +++ b/ui/console.c @@ -331,9 +331,8 @@ void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata) } } -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 = { @@ -345,8 +344,8 @@ static void vga_fill_rect(QemuConsole *con, } /* 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); @@ -526,8 +525,8 @@ static void console_refresh(QemuTextConsole *s) s->text_y[1] = s->height - 1; s->cursor_invalidate = 1; - vga_fill_rect(QEMU_CONSOLE(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; @@ -605,12 +604,12 @@ static void vc_put_lf(VCChardev *vc) s->text_x[1] = s->width - 1; s->text_y[1] = s->height - 1; - vga_bitblt(QEMU_CONSOLE(s), 0, FONT_HEIGHT, 0, 0, - s->width * FONT_WIDTH, - (s->height - 1) * FONT_HEIGHT); - vga_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]); + 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; -- cgit v1.1 From 0a1642e7ccdadf6c3da670369eeceec410dce058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:38:12 +0400 Subject: ui/console: assert(surface) where appropriate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QemuTextConsole code paths assume a surface is being used as scanout, let's make this more explicit. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-39-marcandre.lureau@redhat.com> --- ui/console.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index a157a5b..04ec2d2 100644 --- a/ui/console.c +++ b/ui/console.c @@ -339,6 +339,7 @@ static void qemu_console_fill_rect(QemuConsole *con, int posx, int posy, .x = posx, .y = posy, .width = width, .height = height }; + assert(surface); pixman_image_fill_rectangles(PIXMAN_OP_SRC, surface->image, &color, 1, &rect); } @@ -349,6 +350,7 @@ static void qemu_console_bitblt(QemuConsole *con, { 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); @@ -392,6 +394,7 @@ static void vga_putcharxy(QemuConsole *s, int x, int y, int ch, 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]; @@ -519,6 +522,7 @@ static void console_refresh(QemuTextConsole *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; -- cgit v1.1 From 3f9c21325c4c2005a852744db1016c479d60cb55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:38:13 +0400 Subject: ui/console: fold text_console_update_cursor_timer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230830093843.3531473-40-marcandre.lureau@redhat.com> --- ui/console.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 04ec2d2..0a48ce9 100644 --- a/ui/console.c +++ b/ui/console.c @@ -174,7 +174,6 @@ static QEMUTimer *cursor_timer; 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 bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl); static bool console_compatible_with(QemuConsole *con, @@ -2497,12 +2496,6 @@ static void vc_chr_set_echo(Chardev *chr, bool echo) drv->console->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); -} - static void text_console_update_cursor(void *opaque) { QemuConsole *s; @@ -2520,7 +2513,8 @@ static void text_console_update_cursor(void *opaque) } if (count) { - text_console_update_cursor_timer(); + timer_mod(cursor_timer, + qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2); } } -- cgit v1.1 From 9cb737b77d9cc43a9bed305cbb105928a3dda54b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:38:14 +0400 Subject: ui/vc: skip text console resize when possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function is called on invalidate, on each cursor blink. Avoid the extra copy when the console size didn't change. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-41-marcandre.lureau@redhat.com> --- ui/console.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 0a48ce9..4ee3b77 100644 --- a/ui/console.c +++ b/ui/console.c @@ -413,13 +413,19 @@ 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); + 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 = surface_width(s->surface) / FONT_WIDTH; - t->height = surface_height(s->surface) / FONT_HEIGHT; + t->width = w; + t->height = h; w1 = last_width; if (t->width < w1) -- cgit v1.1 From 893fe23e7dc675d650a4da710efe62a53c2341ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:38:15 +0400 Subject: ui/console: minor stylistic changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-42-marcandre.lureau@redhat.com> --- ui/console.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index 4ee3b77..b1d375e 100644 --- a/ui/console.c +++ b/ui/console.c @@ -427,20 +427,18 @@ static void text_console_resize(QemuTextConsole *t) t->width = w; t->height = h; - w1 = last_width; - if (t->width < w1) - w1 = t->width; + w1 = MIN(t->width, last_width); cells = g_new(TextCell, t->width * t->total_height + 1); - for(y = 0; y < t->total_height; y++) { + for (y = 0; y < t->total_height; y++) { c = &cells[y * t->width]; if (w1 > 0) { c1 = &t->cells[y * last_width]; - for(x = 0; x < w1; x++) { + for (x = 0; x < w1; x++) { *c++ = *c1++; } } - for(x = w1; x < t->width; x++) { + for (x = w1; x < t->width; x++) { c->ch = ' '; c->t_attrib = TEXT_ATTRIBUTES_DEFAULT; c++; -- cgit v1.1 From 322dae4bc817fe288a103427f53de2a945daca27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:38:16 +0400 Subject: ui/vc: move text console invalidate in helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will allow to split the VC code in a separate unit more easily. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-43-marcandre.lureau@redhat.com> --- ui/console.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index b1d375e..ba9da8c 100644 --- a/ui/console.c +++ b/ui/console.c @@ -2500,13 +2500,11 @@ static void vc_chr_set_echo(Chardev *chr, bool echo) 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)) { @@ -2516,7 +2514,14 @@ static void text_console_update_cursor(void *opaque) graphic_hw_invalidate(s); } - if (count) { + return count; +} + +static void text_console_update_cursor(void *opaque) +{ + cursor_visible_phase = !cursor_visible_phase; + + if (qemu_invalidate_text_consoles()) { timer_mod(cursor_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2); } -- cgit v1.1 From 32aa1f8dee3b2e8a4606bc2836a022f1ff5e7f0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:38:17 +0400 Subject: ui/vc: do not parse VC-specific options in Spice and GTK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit 6f974c843c ("gtk: overwrite the console.c char driver"), I shared the VC console parse handler with GTK. And later on in commit d8aec9d9 ("display: add -display spice-app launching a Spice client"), I also used it to handle spice-app VC. This is not necessary, the VC console options (width/height/cols/rows) are specific, and unused by tty-level GTK/Spice VC. This is not a breaking change, as those options are still being parsed by QAPI ChardevVC. Adjust the documentation about it. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-44-marcandre.lureau@redhat.com> --- ui/console.c | 4 ++-- ui/gtk.c | 1 - ui/spice-app.c | 7 ++++++- 3 files changed, 8 insertions(+), 4 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index ba9da8c..e2b0b9c 100644 --- a/ui/console.c +++ b/ui/console.c @@ -2708,7 +2708,7 @@ void qemu_display_help(void) } } -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; @@ -2746,7 +2746,7 @@ 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; diff --git a/ui/gtk.c b/ui/gtk.c index 8ba41c8..ef98bb0 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1860,7 +1860,6 @@ static void char_gd_vc_class_init(ObjectClass *oc, void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); - cc->parse = qemu_chr_parse_vc; cc->open = gd_vc_open; cc->chr_write = gd_vc_chr_write; cc->chr_accept_input = gd_vc_chr_accept_input; diff --git a/ui/spice-app.c b/ui/spice-app.c index ad7f055..405fb7f 100644 --- a/ui/spice-app.c +++ b/ui/spice-app.c @@ -96,6 +96,11 @@ static void vc_chr_set_echo(Chardev *chr, bool echo) /* TODO: set echo for frontends QMP and qtest */ } +static void vc_chr_parse(QemuOpts *opts, ChardevBackend *backend, Error **errp) +{ + /* fqdn is dealt with in vc_chr_open() */ +} + static void char_vc_class_init(ObjectClass *oc, void *data) { VCChardevClass *vc = CHARDEV_VC_CLASS(oc); @@ -103,7 +108,7 @@ static void char_vc_class_init(ObjectClass *oc, void *data) vc->parent_open = cc->open; - cc->parse = qemu_chr_parse_vc; + cc->parse = vc_chr_parse; cc->open = vc_chr_open; cc->chr_set_echo = vc_chr_set_echo; } -- cgit v1.1 From 9db018ac56119ee8e0a87a1a340276e4c8d86392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 30 Aug 2023 13:38:18 +0400 Subject: ui/vc: change the argument for QemuTextConsole MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Those functions are specifc to text/vc console, make that explicit from the argument type. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230830093843.3531473-45-marcandre.lureau@redhat.com> --- ui/console.c | 14 ++++++-------- ui/gtk.c | 2 +- ui/sdl2-input.c | 7 ++++--- ui/sdl2.c | 5 ++--- 4 files changed, 13 insertions(+), 15 deletions(-) (limited to 'ui') diff --git a/ui/console.c b/ui/console.c index e2b0b9c..e4d6179 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1135,16 +1135,12 @@ static void kbd_send_chars(QemuTextConsole *s) } /* called when an ascii key is pressed */ -void kbd_put_keysym_console(QemuConsole *con, int keysym) +void kbd_put_keysym_console(QemuTextConsole *s, int keysym) { - QemuTextConsole *s = (QemuTextConsole *)object_dynamic_cast(OBJECT(con), TYPE_QEMU_TEXT_CONSOLE); uint8_t buf[16], *q; int c; uint32_t num_free; - if (!s) - return; - switch(keysym) { case QEMU_KEY_CTRL_UP: console_scroll(s, -1); @@ -1214,7 +1210,7 @@ static const int ctrl_qcode_to_keysym[Q_KEY_CODE__MAX] = { [Q_KEY_CODE_PGDN] = QEMU_KEY_CTRL_PAGEDOWN, }; -bool kbd_put_qcode_console(QemuConsole *s, int qcode, bool ctrl) +bool kbd_put_qcode_console(QemuTextConsole *s, int qcode, bool ctrl) { int keysym; @@ -1226,7 +1222,7 @@ bool kbd_put_qcode_console(QemuConsole *s, int qcode, bool ctrl) return true; } -void kbd_put_string_console(QemuConsole *s, const char *str, int len) +void kbd_put_string_console(QemuTextConsole *s, const char *str, int len) { int i; @@ -1237,7 +1233,9 @@ void kbd_put_string_console(QemuConsole *s, const char *str, int len) void kbd_put_keysym(int keysym) { - kbd_put_keysym_console(active_console, keysym); + if (QEMU_IS_TEXT_CONSOLE(active_console)) { + kbd_put_keysym_console(QEMU_TEXT_CONSOLE(active_console), keysym); + } } static void text_console_invalidate(void *opaque) diff --git a/ui/gtk.c b/ui/gtk.c index ef98bb0..c34c133 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1187,7 +1187,7 @@ static gboolean gd_text_key_down(GtkWidget *widget, GdkEventKey *key, void *opaque) { VirtualConsole *vc = opaque; - QemuConsole *con = vc->gfx.dcl.con; + QemuTextConsole *con = QEMU_TEXT_CONSOLE(vc->gfx.dcl.con); if (key->keyval == GDK_KEY_Delete) { kbd_put_qcode_console(con, Q_KEY_CODE_DELETE, false); diff --git a/ui/sdl2-input.c b/ui/sdl2-input.c index f068382..a318cc5 100644 --- a/ui/sdl2-input.c +++ b/ui/sdl2-input.c @@ -43,15 +43,16 @@ void sdl2_process_key(struct sdl2_console *scon, ev->type == SDL_KEYDOWN ? "down" : "up"); qkbd_state_key_event(scon->kbd, qcode, ev->type == SDL_KEYDOWN); - if (!qemu_console_is_graphic(con)) { + if (QEMU_IS_TEXT_CONSOLE(con)) { + QemuTextConsole *s = QEMU_TEXT_CONSOLE(con); bool ctrl = qkbd_state_modifier_get(scon->kbd, QKBD_MOD_CTRL); if (ev->type == SDL_KEYDOWN) { switch (qcode) { case Q_KEY_CODE_RET: - kbd_put_keysym_console(con, '\n'); + kbd_put_keysym_console(s, '\n'); break; default: - kbd_put_qcode_console(con, qcode, ctrl); + kbd_put_qcode_console(s, qcode, ctrl); break; } } diff --git a/ui/sdl2.c b/ui/sdl2.c index 0d91b55..16b515f 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -483,10 +483,9 @@ static void handle_textinput(SDL_Event *ev) return; } - if (qemu_console_is_graphic(con)) { - return; + if (QEMU_IS_TEXT_CONSOLE(con)) { + kbd_put_string_console(QEMU_TEXT_CONSOLE(con), ev->text.text, strlen(ev->text.text)); } - kbd_put_string_console(con, ev->text.text, strlen(ev->text.text)); } static void handle_mousemotion(SDL_Event *ev) -- cgit v1.1 From 1663ffb9157e3dc17d14741f6cd6c48bfffde9d0 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 18 Aug 2023 16:10:55 +0100 Subject: ui/spice-display: Avoid dynamic stack allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use an autofree heap allocation instead of a variable-length array on the stack in qemu_spice_create_update(). The codebase has very few VLAs, and if we can get rid of them all we can make the compiler error on new additions. This is a defensive measure against security bugs where an on-stack dynamic allocation isn't correctly size-checked (e.g. CVE-2021-3527). Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-Id: <20230818151057.1541189-2-peter.maydell@linaro.org> --- ui/spice-display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'ui') diff --git a/ui/spice-display.c b/ui/spice-display.c index 3f3f801..0e2fbfb 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -189,7 +189,7 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) { static const int blksize = 32; int blocks = DIV_ROUND_UP(surface_width(ssd->ds), blksize); - int dirty_top[blocks]; + g_autofree int *dirty_top = NULL; int y, yoff1, yoff2, x, xoff, blk, bw; int bpp = surface_bytes_per_pixel(ssd->ds); uint8_t *guest, *mirror; @@ -198,6 +198,7 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) return; }; + dirty_top = g_new(int, blocks); for (blk = 0; blk < blocks; blk++) { dirty_top[blk] = -1; } -- cgit v1.1 From e12acaf75d1ffadfd527180dac798368716a0001 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 18 Aug 2023 16:10:56 +0100 Subject: ui/vnc-enc-hextile: Use static rather than dynamic length stack array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the send_hextile_tile_* function we create a variable length array data[]. In fact we know that the client_pf.bytes_per_pixel is at most 4 (enforced by set_pixel_format()), so we can make the array a compile-time fixed length of 1536 bytes. The codebase has very few VLAs, and if we can get rid of them all we can make the compiler error on new additions. This is a defensive measure against security bugs where an on-stack dynamic allocation isn't correctly size-checked (e.g. CVE-2021-3527). Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé [ Marc-André - rename BPP to MAX_BYTES_PER_PIXEL ] Signed-off-by: Marc-André Lureau Message-Id: <20230818151057.1541189-3-peter.maydell@linaro.org> --- ui/vnc-enc-hextile-template.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'ui') diff --git a/ui/vnc-enc-hextile-template.h b/ui/vnc-enc-hextile-template.h index 0c56262..8ee9208 100644 --- a/ui/vnc-enc-hextile-template.h +++ b/ui/vnc-enc-hextile-template.h @@ -7,6 +7,8 @@ #define NAME BPP #endif +#define MAX_BYTES_PER_PIXEL 4 + static void CONCAT(send_hextile_tile_, NAME)(VncState *vs, int x, int y, int w, int h, void *last_bg_, @@ -25,10 +27,13 @@ static void CONCAT(send_hextile_tile_, NAME)(VncState *vs, int bg_count = 0; int fg_count = 0; int flags = 0; - uint8_t data[(vs->client_pf.bytes_per_pixel + 2) * 16 * 16]; + uint8_t data[(MAX_BYTES_PER_PIXEL + 2) * 16 * 16]; int n_data = 0; int n_subtiles = 0; + /* Enforced by set_pixel_format() */ + assert(vs->client_pf.bytes_per_pixel <= MAX_BYTES_PER_PIXEL); + for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { switch (n_colors) { @@ -205,6 +210,7 @@ static void CONCAT(send_hextile_tile_, NAME)(VncState *vs, } } +#undef MAX_BYTES_PER_PIXEL #undef NAME #undef pixel_t #undef CONCAT_I -- cgit v1.1 From dd0439e1496ad326dcaa7dc67f91f2e6f6c4930b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 18 Aug 2023 16:10:57 +0100 Subject: ui/vnc-enc-tight: Avoid dynamic stack allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use autofree heap allocation instead of variable-length array on the stack. The codebase has very few VLAs, and if we can get rid of them all we can make the compiler error on new additions. This is a defensive measure against security bugs where an on-stack dynamic allocation isn't correctly size-checked (e.g. CVE-2021-3527). Signed-off-by: Philippe Mathieu-Daudé [PMM: expanded commit message] Signed-off-by: Peter Maydell Reviewed-by: Francisco Iglesias Reviewed-by: Marc-André Lureau Message-Id: <20230818151057.1541189-4-peter.maydell@linaro.org> --- ui/vnc-enc-tight.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'ui') diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index ee853dc..41f559e 100644 --- a/ui/vnc-enc-tight.c +++ b/ui/vnc-enc-tight.c @@ -1097,13 +1097,13 @@ static int send_palette_rect(VncState *vs, int x, int y, switch (vs->client_pf.bytes_per_pixel) { case 4: { - size_t old_offset, offset; - uint32_t header[palette_size(palette)]; + size_t old_offset, offset, palette_sz = palette_size(palette); + g_autofree uint32_t *header = g_new(uint32_t, palette_sz); struct palette_cb_priv priv = { vs, (uint8_t *)header }; old_offset = vs->output.offset; palette_iter(palette, write_palette, &priv); - vnc_write(vs, header, sizeof(header)); + vnc_write(vs, header, palette_sz * sizeof(uint32_t)); if (vs->tight->pixel24) { tight_pack24(vs, vs->output.buffer + old_offset, colors, &offset); @@ -1115,11 +1115,12 @@ static int send_palette_rect(VncState *vs, int x, int y, } case 2: { - uint16_t header[palette_size(palette)]; + size_t palette_sz = palette_size(palette); + g_autofree uint16_t *header = g_new(uint16_t, palette_sz); struct palette_cb_priv priv = { vs, (uint8_t *)header }; palette_iter(palette, write_palette, &priv); - vnc_write(vs, header, sizeof(header)); + vnc_write(vs, header, palette_sz * sizeof(uint16_t)); tight_encode_indexed_rect16(vs->tight->tight.buffer, w * h, palette); break; } -- cgit v1.1 From cb6ccdc9ca705cd8c3ef50e51c16a3732c2fa734 Mon Sep 17 00:00:00 2001 From: Bilal Elmoussaoui Date: Fri, 1 Sep 2023 14:45:07 +0200 Subject: ui/dbus: Properly dispose touch/mouse dbus objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: 142ca628a7 ("ui: add a D-Bus display backend") Fixes: de9f844ce2 ("ui/dbus: Expose a touch device interface") Signed-off-by: Bilal Elmoussaoui Reviewed-by: Marc-André Lureau Message-Id: <20230901124507.94087-1-belmouss@redhat.com> --- ui/dbus-console.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'ui') diff --git a/ui/dbus-console.c b/ui/dbus-console.c index e19774f..36f7349 100644 --- a/ui/dbus-console.c +++ b/ui/dbus-console.c @@ -150,6 +150,8 @@ dbus_display_console_dispose(GObject *object) DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(object); unregister_displaychangelistener(&ddc->dcl); + g_clear_object(&ddc->iface_touch); + g_clear_object(&ddc->iface_mouse); g_clear_object(&ddc->iface_kbd); g_clear_object(&ddc->iface); g_clear_pointer(&ddc->listeners, g_hash_table_unref); -- cgit v1.1 From 7007e98c4ba443ce5d42acf851daaa1835b18e83 Mon Sep 17 00:00:00 2001 From: Bilal Elmoussaoui Date: Mon, 14 Aug 2023 14:58:02 +0200 Subject: ui/dbus: implement damage regions for GL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, when using `-display dbus,gl=on` all updates to the client become "full scanout" updates, meaning there is no way for the client to limit damage regions to the display server. Instead of using an "update count", this patch tracks the damage region and propagates it to the client. This was less of an issue when clients were using GtkGLArea for rendering, as you'd be doing full-surface redraw. To be efficient, the client needs both a DMA-BUF and the damage region to be updated. Co-authored-by: Christian Hergert Signed-off-by: Bilal Elmoussaoui Reviewed-by: Marc-André Lureau Message-Id: <20230814125802.102160-1-belmouss@redhat.com> --- ui/dbus-listener.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) (limited to 'ui') diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c index 3091727..36548a7 100644 --- a/ui/dbus-listener.c +++ b/ui/dbus-listener.c @@ -26,6 +26,9 @@ #include "qapi/error.h" #include "sysemu/sysemu.h" #include "dbus.h" +#ifdef CONFIG_OPENGL +#include +#endif #ifdef G_OS_UNIX #include #endif @@ -59,12 +62,15 @@ struct _DBusDisplayListener { QemuDBusDisplay1Listener *proxy; +#ifdef CONFIG_OPENGL + /* Keep track of the damage region */ + pixman_region32_t gl_damage; +#endif + DisplayChangeListener dcl; DisplaySurface *ds; enum share_kind ds_share; - int gl_updates; - bool ds_mapped; bool can_share_map; @@ -539,11 +545,16 @@ static void dbus_gl_refresh(DisplayChangeListener *dcl) return; } - if (ddl->gl_updates) { - dbus_call_update_gl(dcl, 0, 0, - surface_width(ddl->ds), surface_height(ddl->ds)); - ddl->gl_updates = 0; + int n_rects = pixman_region32_n_rects(&ddl->gl_damage); + + for (int i = 0; i < n_rects; i++) { + pixman_box32_t *box; + box = pixman_region32_rectangles(&ddl->gl_damage, NULL) + i; + /* TODO: Add a UpdateList call to send multiple updates at once */ + dbus_call_update_gl(dcl, box->x1, box->y1, + box->x2 - box->x1, box->y2 - box->y1); } + pixman_region32_clear(&ddl->gl_damage); } #endif /* OPENGL */ @@ -558,7 +569,10 @@ static void dbus_gl_gfx_update(DisplayChangeListener *dcl, { DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl); - ddl->gl_updates++; + pixman_region32_t rect_region; + pixman_region32_init_rect(&rect_region, x, y, w, h); + pixman_region32_union(&ddl->gl_damage, &ddl->gl_damage, &rect_region); + pixman_region32_fini(&rect_region); } #endif @@ -738,6 +752,7 @@ dbus_display_listener_dispose(GObject *object) g_clear_object(&ddl->d3d11_proxy); g_clear_pointer(&ddl->peer_process, CloseHandle); #ifdef CONFIG_OPENGL + pixman_region32_fini(&ddl->gl_damage); egl_fb_destroy(&ddl->fb); #endif #endif @@ -772,6 +787,9 @@ dbus_display_listener_class_init(DBusDisplayListenerClass *klass) static void dbus_display_listener_init(DBusDisplayListener *ddl) { +#ifdef CONFIG_OPENGL + pixman_region32_init(&ddl->gl_damage); +#endif } const char * -- cgit v1.1 From 1b4fd51656556646b1a0842e596cb606d73e26cf Mon Sep 17 00:00:00 2001 From: Guoyi Tu Date: Thu, 17 Aug 2023 22:12:52 +0800 Subject: ui/vdagent: call vdagent_disconnect() when agent connection is lost MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit when the agent connection is lost, the input handler of the mouse doesn't deactivate, which results in unresponsive mouse events in VNC windows. To fix this issue, call vdagent_disconnect() to reset the state each time the frontend disconncect Signed-off-by: Guoyi Tu Signed-off-by: dengpengcheng Reviewed-by: Marc-André Lureau Message-Id: <71fd5a58fd09f10cdb35f167b2edb5669300116e.1692281173.git.tugy@chinatelecom.cn> --- ui/vdagent.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'ui') diff --git a/ui/vdagent.c b/ui/vdagent.c index 8a65149..4b9a1fb 100644 --- a/ui/vdagent.c +++ b/ui/vdagent.c @@ -870,8 +870,11 @@ static void vdagent_disconnect(VDAgentChardev *vd) static void vdagent_chr_set_fe_open(struct Chardev *chr, int fe_open) { + VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(chr); + if (!fe_open) { trace_vdagent_close(); + vdagent_disconnect(vd); /* To reset_serial, we CLOSED our side. Make sure the other end knows we * are ready again. */ qemu_chr_be_event(chr, CHR_EVENT_OPENED); -- cgit v1.1 From 878490937c6273f27191e3a195c7a60fa68819b8 Mon Sep 17 00:00:00 2001 From: Guoyi Tu Date: Thu, 17 Aug 2023 22:12:53 +0800 Subject: ui/vdagent: Unregister input handler of mouse during finalization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Input handler resource should be released when VDAgentChardev object finalize Signed-off-by: Guoyi Tu Signed-off-by: dengpengcheng Reviewed-by: Marc-André Lureau Message-Id: --- ui/vdagent.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'ui') diff --git a/ui/vdagent.c b/ui/vdagent.c index 4b9a1fb..00d36a8 100644 --- a/ui/vdagent.c +++ b/ui/vdagent.c @@ -926,6 +926,9 @@ static void vdagent_chr_fini(Object *obj) migrate_del_blocker(vd->migration_blocker); vdagent_disconnect(vd); + if (vd->mouse_hs) { + qemu_input_handler_unregister(vd->mouse_hs); + } buffer_free(&vd->outbuf); error_free(vd->migration_blocker); } -- cgit v1.1 From e38f4e976dd40c985bfe84230a627de9a108c9d3 Mon Sep 17 00:00:00 2001 From: Dmitry Frolov Date: Fri, 25 Aug 2023 14:58:19 +0300 Subject: ui/gtk: fix leaks found wtih fuzzing It is true, that there is no problem during runtime from the first sight, because the memory is lost just before qemu exits. Nevertheless, this change is necessary, because AddressSanitizer is not able to recognize this situation and produces crash-report (which is false-positive in fact). Lots of False-Positive warnings are davaluing problems, found with fuzzing, and thus the whole methodology of dynamic analysis. This patch eliminates such False-Positive reports, and makes every problem, found with fuzzing, more valuable. Fixes: 060ab76356 ("gtk: don't exit early in case gtk init fails") Signed-off-by: Dmitry Frolov Reviewed-by: Michael Tokarev Message-Id: <20230825115818.1091936-1-frolov@swemel.ru> --- ui/gtk.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'ui') diff --git a/ui/gtk.c b/ui/gtk.c index c34c133..a14d561 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -2359,7 +2359,7 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts) { VirtualConsole *vc; - GtkDisplayState *s = g_malloc0(sizeof(*s)); + GtkDisplayState *s; GdkDisplay *window_display; GtkIconTheme *theme; char *dir; @@ -2369,6 +2369,7 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts) exit(1); } assert(opts->type == DISPLAY_TYPE_GTK); + s = g_malloc0(sizeof(*s)); s->opts = opts; theme = gtk_icon_theme_get_default(); -- cgit v1.1