Hi
On Thu, Jun 11, 2026 at 12:03 PM Akihiko Odaki
<[email protected]> wrote:
>
> On 2026/06/08 16:16, Marc-André Lureau wrote:
> > Register a console notifier so the GTK display dynamically creates and
> > destroys VirtualConsole tabs when graphic consoles are added or removed
> > at runtime (e.g. vfio-pci with display=on hotplug).
> >
> > Add skips consoles that already have a VC binding, remove skips unknown
> > consoles.
> >
> > Signed-off-by: Marc-André Lureau <[email protected]>
> > ---
> > include/ui/gtk.h | 1 +
> > ui/gtk.c | 77
> > +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> > 2 files changed, 77 insertions(+), 1 deletion(-)
> >
> > diff --git a/include/ui/gtk.h b/include/ui/gtk.h
> > index b0be5070795..6cb611ce474 100644
> > --- a/include/ui/gtk.h
> > +++ b/include/ui/gtk.h
> > @@ -140,6 +140,7 @@ struct GtkDisplayState {
> >
> > GdkCursor *null_cursor;
> > Notifier mouse_mode_notifier;
> > + Notifier console_notifier;
> > gboolean free_scale;
> > gboolean keep_aspect_ratio;
> >
> > diff --git a/ui/gtk.c b/ui/gtk.c
> > index 6325704c397..6ef58d1367c 100644
> > --- a/ui/gtk.c
> > +++ b/ui/gtk.c
> > @@ -2332,7 +2332,8 @@ static bool gd_scale_valid(double scale)
> > return scale >= VC_SCALE_MIN && scale <= VC_SCALE_MAX;
> > }
> >
> > -static void add_gfx_console(GtkDisplayState *s, QemuConsole *con)
> > +static VirtualConsole *
> > +add_gfx_console(GtkDisplayState *s, QemuConsole *con)
> > {
> > VirtualConsole *vc = g_new0(VirtualConsole, 1);
> > const DisplayChangeListenerOps *ops = &dcl_ops;
> > @@ -2414,6 +2415,76 @@ static void add_gfx_console(GtkDisplayState *s,
> > QemuConsole *con)
> > qemu_console_register_listener(con, &vc->gfx.dcl, ops);
> >
> > gd_connect_vc_gfx_signals(vc);
> > + return vc;
> > +}
> > +
> > +static void gd_vc_add_gfx(GtkDisplayState *s, QemuConsole *con)
> > +{
> > + VirtualConsole *vc;
> > + int i;
> > +
> > + for (i = 0; i < (int)s->vcs->len; i++) {
> > + VirtualConsole *v = g_ptr_array_index(s->vcs, i);
> > + if (v->type == GD_VC_GFX && v->gfx.dcl.con == con) {
> > + return;
> > + }
> > + }
> > +
> > + vc = add_gfx_console(s, con);
> > + gtk_widget_show_all(vc->tab_item);
> > + gtk_widget_realize(vc->gfx.drawing_area);
> > +
> > + if (s->free_scale) {
> > + gd_update_windowsize(vc);
> > + }
> > +
> > + gd_update_caption(s);
> > + gd_rebuild_vc_menu(s);
> > +
> > + gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), true);
>
> This ignores the user-specified show-tabs configuration.
true, that was useful for testing, but I should have dropped it.
> Regards,
> Akihiko Odaki
>
> > +}
> > +
> > +static void gd_vc_remove_gfx(GtkDisplayState *s, QemuConsole *con)
> > +{
> > + VirtualConsole *vc = NULL;
> > + guint idx;
> > +
> > + for (idx = 0; idx < s->vcs->len; idx++) {
> > + VirtualConsole *v = g_ptr_array_index(s->vcs, idx);
> > + if (v->type == GD_VC_GFX && v->gfx.dcl.con == con) {
> > + vc = v;
> > + break;
> > + }
> > + }
> > + if (!vc) {
> > + return;
> > + }
> > +
> > + if (s->kbd_owner == vc) {
> > + gd_ungrab_keyboard(s);
> > + }
> > + if (s->ptr_owner == vc) {
> > + gd_ungrab_pointer(s);
> > + }
> > +
> > + g_ptr_array_remove_index(s->vcs, idx);
> > + gd_rebuild_vc_menu(s);
> > + gd_update_caption(s);
> > +}
> > +
> > +static void gd_console_notify(Notifier *n, void *data)
> > +{
> > + GtkDisplayState *s = container_of(n, GtkDisplayState,
> > console_notifier);
> > + QemuConsoleEvent *event = data;
> > +
> > + switch (event->type) {
> > + case QEMU_CONSOLE_ADDED:
> > + gd_vc_add_gfx(s, event->con);
> > + break;
> > + case QEMU_CONSOLE_REMOVED:
> > + gd_vc_remove_gfx(s, event->con);
> > + break;
> > + }
> > }
> >
> > static void gd_create_menu_view(GtkDisplayState *s, DisplayOptions *opts)
> > @@ -2688,6 +2759,9 @@ static void gtk_display_init(DisplayState *ds,
> > DisplayOptions *opts)
> >
> > gd_create_menus(s, opts);
> >
> > + s->console_notifier.notify = gd_console_notify;
> > + qemu_console_add_notifier(&s->console_notifier);
> > +
> > gd_connect_signals(s);
> >
> > gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
> > @@ -2808,6 +2882,7 @@ static void gtk_display_cleanup(void)
> > return;
> > }
> >
> > + qemu_console_remove_notifier(&s->console_notifier);
> > qemu_remove_mouse_mode_change_notifier(&s->mouse_mode_notifier);
> > gd_clipboard_cleanup(s);
> > g_signal_handlers_disconnect_by_func(s->notebook,
> >
>
>