Commit e12c1693bd for qemu.org
commit e12c1693bde22b35e008d60dda4babefd5c254ed
Author: Christian Quante <christian@quante.one>
Date: Thu Oct 22 15:43:32 2026 +0200
ui/dbus: send a Scanout before the first Update of a new surface
Without OpenGL and without shared memory, the D-Bus listener sends a
Scanout only for an update that covers the whole surface, and
dbus_gfx_switch() only records the new surface. So when a device draws
a new surface in parts, the client gets Updates for a size that no
Scanout has given it. VGA text mode is such a device: vga_draw_text()
sends one update per row of characters, so a text mode that changes its
size does not send a Scanout. According to ui/dbus-display1.xml, Update
is only called after a Scanout call, and Scanout is the call that
resizes the display.
The client can learn the new size only from the Width and Height
properties of the Console. They come on a different connection, and
the generated skeleton sends PropertiesChanged from an idle callback,
after the redraw. A client that sets up a new buffer when this signal
comes loses the rows that came before it. VGA text mode does not send
them again: it redraws only the characters that change, and all of
them only after changes such as a new font or palette, or with blinking
enabled.
The Windows NT 4.0 setup shows this. With blinking off, it changes the
character height from 16 to 12 lines (720x400 to 720x396), and in a
D-Bus client large parts of its blue background stayed black.
With shared memory, dbus_scanout_map() already sends ScanoutMap with the
new size at the first update after a surface switch. Do the same without
shared memory: the first update after a switch sends a Scanout of the
whole surface.
Signed-off-by: Christian Quante <christian@quante.one>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-ID: <20261022134335.12241-2-christian@quante.one>
diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c
index 624d0fb71d..26ed84d700 100644
--- a/ui/dbus-listener.c
+++ b/ui/dbus-listener.c
@@ -71,6 +71,8 @@ struct _DBusDisplayListener {
DisplayChangeListener dcl;
DisplaySurface *ds;
enum share_kind ds_share;
+ /* true until a Scanout or ScanoutMap of ds has been sent */
+ bool ds_scanout_pending;
bool ds_mapped;
bool can_share_map;
@@ -480,6 +482,7 @@ static bool dbus_scanout_map(DBusDisplayListener *ddl)
}
ddl->ds_share = SHARE_KIND_MAPPED;
+ ddl->ds_scanout_pending = false;
return true;
}
@@ -591,6 +594,7 @@ static bool dbus_scanout_map(DBusDisplayListener *ddl)
}
ddl->ds_share = SHARE_KIND_MAPPED;
+ ddl->ds_scanout_pending = false;
return true;
}
@@ -844,6 +848,7 @@ static void ddl_scanout(DBusDisplayListener *ddl)
ddl->proxy, surface_width(ddl->ds), surface_height(ddl->ds),
surface_stride(ddl->ds), surface_format(ddl->ds), v_data,
G_DBUS_CALL_FLAGS_NONE, DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
+ ddl->ds_scanout_pending = false;
}
static void dbus_gfx_update(DisplayChangeListener *dcl,
@@ -872,7 +877,9 @@ static void dbus_gfx_update(DisplayChangeListener *dcl,
return;
}
- if (x == 0 && y == 0 && w == surface_width(ddl->ds) && h == surface_height(ddl->ds)) {
+ if (ddl->ds_scanout_pending ||
+ (x == 0 && y == 0 &&
+ w == surface_width(ddl->ds) && h == surface_height(ddl->ds))) {
return ddl_scanout(ddl);
}
@@ -907,6 +914,7 @@ static void dbus_gfx_switch(DisplayChangeListener *dcl,
ddl->ds = new_surface;
ddl->ds_share = SHARE_KIND_NONE;
+ ddl->ds_scanout_pending = true;
}
static void dbus_mouse_set(DisplayChangeListener *dcl,