UI patch queue

- misc fixes and improvement
 - cleanups and refactoring in ui/vc code
 -----BEGIN PGP SIGNATURE-----
 
 iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmT1wuYcHG1hcmNhbmRy
 ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5UhmD/wPCVZ/Vipmbexc8eBd
 wbI7i0zR5Hj7szU4D1MV+fvi5Y6Z7PWvPxnQOIoWbmEGuhOm5P73oRz1jlBDXGLP
 Nh1kh2RvuWILF0Vu+QjJHL5FyA0XJcl/Qhsn1tc7pYMbEOBCpPfpmWRiXrEUDc7/
 S1iSPkB2a7YYwuMW6ksPyKlsb4tjGyea/HYz1lTdw8bJxaFVXMFX35lrqz+A5ZGz
 XAk/6OyMtkMbBi8hWcd6IweYyc/DYaK8emqppQLIUenZEz7nKSWlEUIKcXpf9U4n
 3W+BISACxnw7KbXrrZl2KJf2Bix6LRureoscZTKawnB/D5hV+g7PtEjNMUQsxjg3
 RyV9+zSPsIg5zXunrHIs1rrUtGS5SvdQbIQYqHPNdL86iuWKer+EnwA06vflweLw
 P7FZhuBNvuY3gU2sdCk5Q7My92YT5DRWjoJRHLFGNYTxPA6MYPivIu8RqsBiu+JX
 BvK1FfhG2JsR9XuuOFR968AXLfMc0hOlHfHWvORk3s/9zIpeEWmQbnGxr1sN9El8
 o+rDIkcadELuzcTJcoHCKdCzjFbLdNNKgvbcVQdw3rdp2rvQ6CZalyh+qZEihAy4
 xLVO+hUypxNhRAg/DtZilUW6cPavn0OjoH/3BgY0F0GiwvhFMntyVGN7eBdwnC7c
 sV5s4Xnafmh5xnGf0GS3UyuX9g==
 =JxZP
 -----END PGP SIGNATURE-----

Merge tag 'ui-pull-request' of https://gitlab.com/marcandre.lureau/qemu into staging

UI patch queue

- misc fixes and improvement
- cleanups and refactoring in ui/vc code

# -----BEGIN PGP SIGNATURE-----
#
# iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmT1wuYcHG1hcmNhbmRy
# ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5UhmD/wPCVZ/Vipmbexc8eBd
# wbI7i0zR5Hj7szU4D1MV+fvi5Y6Z7PWvPxnQOIoWbmEGuhOm5P73oRz1jlBDXGLP
# Nh1kh2RvuWILF0Vu+QjJHL5FyA0XJcl/Qhsn1tc7pYMbEOBCpPfpmWRiXrEUDc7/
# S1iSPkB2a7YYwuMW6ksPyKlsb4tjGyea/HYz1lTdw8bJxaFVXMFX35lrqz+A5ZGz
# XAk/6OyMtkMbBi8hWcd6IweYyc/DYaK8emqppQLIUenZEz7nKSWlEUIKcXpf9U4n
# 3W+BISACxnw7KbXrrZl2KJf2Bix6LRureoscZTKawnB/D5hV+g7PtEjNMUQsxjg3
# RyV9+zSPsIg5zXunrHIs1rrUtGS5SvdQbIQYqHPNdL86iuWKer+EnwA06vflweLw
# P7FZhuBNvuY3gU2sdCk5Q7My92YT5DRWjoJRHLFGNYTxPA6MYPivIu8RqsBiu+JX
# BvK1FfhG2JsR9XuuOFR968AXLfMc0hOlHfHWvORk3s/9zIpeEWmQbnGxr1sN9El8
# o+rDIkcadELuzcTJcoHCKdCzjFbLdNNKgvbcVQdw3rdp2rvQ6CZalyh+qZEihAy4
# xLVO+hUypxNhRAg/DtZilUW6cPavn0OjoH/3BgY0F0GiwvhFMntyVGN7eBdwnC7c
# sV5s4Xnafmh5xnGf0GS3UyuX9g==
# =JxZP
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 04 Sep 2023 07:43:34 EDT
# gpg:                using RSA key 87A9BD933F87C606D276F62DDAE8E10975969CE5
# gpg:                issuer "marcandre.lureau@redhat.com"
# gpg: Good signature from "Marc-André Lureau <marcandre.lureau@redhat.com>" [full]
# gpg:                 aka "Marc-André Lureau <marcandre.lureau@gmail.com>" [full]
# Primary key fingerprint: 87A9 BD93 3F87 C606 D276  F62D DAE8 E109 7596 9CE5

* tag 'ui-pull-request' of https://gitlab.com/marcandre.lureau/qemu: (52 commits)
  ui/gtk: fix leaks found wtih fuzzing
  ui/vdagent: Unregister input handler of mouse during finalization
  ui/vdagent: call vdagent_disconnect() when agent connection is lost
  ui/dbus: implement damage regions for GL
  ui/dbus: Properly dispose touch/mouse dbus objects
  ui/vnc-enc-tight: Avoid dynamic stack allocation
  ui/vnc-enc-hextile: Use static rather than dynamic length stack array
  ui/spice-display: Avoid dynamic stack allocation
  ui/vc: change the argument for QemuTextConsole
  ui/vc: do not parse VC-specific options in Spice and GTK
  ui/vc: move text console invalidate in helper
  ui/console: minor stylistic changes
  ui/vc: skip text console resize when possible
  ui/console: fold text_console_update_cursor_timer
  ui/console: assert(surface) where appropriate
  ui/console: rename vga_ functions with qemu_console_
  ui/console: use QEMU_PIXMAN_COLOR helpers
  ui/console: declare console types in console.h
  ui/vc: use common text console surface creation
  ui/console: remove need for g_width/g_height
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
master
Stefan Hajnoczi 2023-09-06 11:16:00 -04:00
commit c152379422
17 changed files with 776 additions and 692 deletions

View File

@ -320,7 +320,4 @@ GSource *qemu_chr_timeout_add_ms(Chardev *chr, guint ms,
void suspend_mux_open(void);
void resume_mux_open(void);
/* console.c */
void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, Error **errp);
#endif

View File

@ -12,6 +12,27 @@
# include "ui/shader.h"
#endif
#define TYPE_QEMU_CONSOLE "qemu-console"
OBJECT_DECLARE_TYPE(QemuConsole, QemuConsoleClass, QEMU_CONSOLE)
#define TYPE_QEMU_GRAPHIC_CONSOLE "qemu-graphic-console"
OBJECT_DECLARE_SIMPLE_TYPE(QemuGraphicConsole, QEMU_GRAPHIC_CONSOLE)
#define TYPE_QEMU_TEXT_CONSOLE "qemu-text-console"
OBJECT_DECLARE_SIMPLE_TYPE(QemuTextConsole, QEMU_TEXT_CONSOLE)
#define TYPE_QEMU_FIXED_TEXT_CONSOLE "qemu-fixed-text-console"
OBJECT_DECLARE_SIMPLE_TYPE(QemuFixedTextConsole, QEMU_FIXED_TEXT_CONSOLE)
#define QEMU_IS_GRAPHIC_CONSOLE(c) \
object_dynamic_cast(OBJECT(c), TYPE_QEMU_GRAPHIC_CONSOLE)
#define QEMU_IS_TEXT_CONSOLE(c) \
object_dynamic_cast(OBJECT(c), TYPE_QEMU_TEXT_CONSOLE)
#define QEMU_IS_FIXED_TEXT_CONSOLE(c) \
object_dynamic_cast(OBJECT(c), TYPE_QEMU_FIXED_TEXT_CONSOLE)
/* keyboard/mouse support */
#define MOUSE_EVENT_LBUTTON 0x01
@ -91,9 +112,9 @@ bool qemu_mouse_set(int index, Error **errp);
#define QEMU_KEY_CTRL_PAGEUP 0xe406
#define QEMU_KEY_CTRL_PAGEDOWN 0xe407
void kbd_put_keysym_console(QemuConsole *s, int keysym);
bool kbd_put_qcode_console(QemuConsole *s, int qcode, bool ctrl);
void kbd_put_string_console(QemuConsole *s, const char *str, int len);
void kbd_put_keysym_console(QemuTextConsole *s, int keysym);
bool kbd_put_qcode_console(QemuTextConsole *s, int qcode, bool ctrl);
void kbd_put_string_console(QemuTextConsole *s, const char *str, int len);
void kbd_put_keysym(int keysym);
/* Touch devices */
@ -112,10 +133,6 @@ void console_handle_touch_event(QemuConsole *con,
Error **errp);
/* consoles */
#define TYPE_QEMU_CONSOLE "qemu-console"
OBJECT_DECLARE_TYPE(QemuConsole, QemuConsoleClass, QEMU_CONSOLE)
struct QemuConsoleClass {
ObjectClass parent_class;
};
@ -484,7 +501,6 @@ QemuConsole *qemu_console_lookup_by_index(unsigned int index);
QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head);
QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
uint32_t head, Error **errp);
QemuConsole *qemu_console_lookup_unused(void);
QEMUCursor *qemu_console_get_cursor(QemuConsole *con);
bool qemu_console_is_visible(QemuConsole *con);
bool qemu_console_is_graphic(QemuConsole *con);
@ -504,6 +520,8 @@ void qemu_console_set_window_id(QemuConsole *con, int window_id);
void console_select(unsigned int index);
void qemu_console_resize(QemuConsole *con, int width, int height);
DisplaySurface *qemu_console_surface(QemuConsole *con);
void coroutine_fn qemu_console_co_wait_update(QemuConsole *con);
int qemu_invalidate_text_consoles(void);
/* console-gl.c */
#ifdef CONFIG_OPENGL

View File

@ -47,6 +47,12 @@
# define PIXMAN_LE_x8r8g8b8 PIXMAN_x8r8g8b8
#endif
#define QEMU_PIXMAN_COLOR(r, g, b) \
{ .red = r << 8, .green = g << 8, .blue = b << 8, .alpha = 0xffff }
#define QEMU_PIXMAN_COLOR_BLACK QEMU_PIXMAN_COLOR(0x00, 0x00, 0x00)
#define QEMU_PIXMAN_COLOR_GRAY QEMU_PIXMAN_COLOR(0xaa, 0xaa, 0xaa)
/* -------------------------------------------------------------------- */
typedef struct PixelFormat {
@ -72,13 +78,10 @@ pixman_image_t *qemu_pixman_linebuf_create(pixman_format_code_t format,
int width);
void qemu_pixman_linebuf_fill(pixman_image_t *linebuf, pixman_image_t *fb,
int width, int x, int y);
void qemu_pixman_linebuf_copy(pixman_image_t *fb, int width, int x, int y,
pixman_image_t *linebuf);
pixman_image_t *qemu_pixman_mirror_create(pixman_format_code_t format,
pixman_image_t *image);
void qemu_pixman_image_unref(pixman_image_t *image);
pixman_color_t qemu_pixman_color(PixelFormat *pf, uint32_t color);
pixman_image_t *qemu_pixman_glyph_from_vgafont(int height, const uint8_t *font,
unsigned int ch);
void qemu_pixman_glyph_render(pixman_image_t *glyph,

View File

@ -390,6 +390,10 @@
#
# @rows: console height, in chars
#
# Note: the options are only effective when the VNC or SDL graphical
# display backend is active. They are ignored with the GTK, Spice, VNC
# and D-Bus display backends.
#
# Since: 1.5
##
{ 'struct': 'ChardevVC',

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -26,6 +26,9 @@
#include "qapi/error.h"
#include "sysemu/sysemu.h"
#include "dbus.h"
#ifdef CONFIG_OPENGL
#include <pixman.h>
#endif
#ifdef G_OS_UNIX
#include <gio/gunixfdlist.h>
#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 *

View File

@ -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);
@ -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;
@ -2360,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;
@ -2370,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();

View File

@ -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)
{
@ -226,17 +218,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)
{

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 <png.h>
#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);
}
}
}

View File

@ -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);
@ -923,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);
}

View File

@ -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

View File

@ -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;
}