ui/gtk: convert VirtualConsole storage from fixed array to GPtrArray
Replace the fixed-size vc[MAX_VCS] with GPtrArray. This is a preparatory refactoring for console hotplug support, which needs to add/remove VCs dynamically. Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-ID: <20260623-b4-ui-v4-26-4656aec3398d@redhat.com>
Marc-André Lureau committed
Jun 23, 2026 at 11:44 UTC
50cff68a63815e6ce62efb7fff7adce0b24cee98
2 files changed
+87
-24
include/ui/gtk.h
+1
-2
@@ -118,8 +118,7 @@ struct GtkDisplayState {
118
GtkWidget *grab_item;
119
GtkWidget *grab_on_hover_item;
120
121
- int nb_vcs;
122
- VirtualConsole vc[MAX_VCS];
121
+ GPtrArray *vcs;
122
123
GtkWidget *show_tabs_item;
124
GtkWidget *untabify_item;
ui/gtk.c
+86
-22
@@ -150,8 +150,8 @@ static VirtualConsole *gd_vc_find_by_menu(GtkDisplayState *s)
150
VirtualConsole *vc;
151
gint i;
152
153
- for (i = 0; i < s->nb_vcs; i++) {
154
- vc = &s->vc[i];
153
+ for (i = 0; i < s->vcs->len; i++) {
154
+ vc = g_ptr_array_index(s->vcs, i);
155
if (gtk_check_menu_item_get_active
156
(GTK_CHECK_MENU_ITEM(vc->menu_item))) {
157
return vc;
@@ -165,8 +165,11 @@ static VirtualConsole *gd_vc_find_by_page(GtkDisplayState *s, gint page)
165
VirtualConsole *vc;
166
gint i, p;
167
168
- for (i = 0; i < s->nb_vcs; i++) {
169
- vc = &s->vc[i];
168
+ if (!s->vcs) {
169
+ return NULL;
170
+ }
171
+ for (i = 0; i < s->vcs->len; i++) {
172
+ vc = g_ptr_array_index(s->vcs, i);
173
p = gtk_notebook_page_num(GTK_NOTEBOOK(s->notebook), vc->tab_item);
174
if (p == page) {
175
return vc;
@@ -247,8 +250,8 @@ static void gd_update_caption(GtkDisplayState *s)
250
gtk_window_set_title(GTK_WINDOW(s->window), title);
251
g_free(title);
252
250
- for (i = 0; i < s->nb_vcs; i++) {
251
- VirtualConsole *vc = &s->vc[i];
253
+ for (i = 0; i < s->vcs->len; i++) {
254
+ VirtualConsole *vc = g_ptr_array_index(s->vcs, i);
255
256
if (!vc->window) {
257
continue;
@@ -357,7 +360,7 @@ static void gtk_release_modifiers(GtkDisplayState *s)
360
{
361
VirtualConsole *vc = gd_vc_find_current(s);
362
360
- if (vc->type != GD_VC_GFX ||
363
+ if (!vc || vc->type != GD_VC_GFX ||
364
!qemu_console_is_graphic(vc->gfx.dcl.con)) {
365
return;
366
}
@@ -702,8 +705,8 @@ static void gd_mouse_mode_change(Notifier *notify, void *data)
705
gd_ungrab_pointer(s);
706
}
707
}
705
- for (i = 0; i < s->nb_vcs; i++) {
706
- VirtualConsole *vc = &s->vc[i];
708
+ for (i = 0; i < s->vcs->len; i++) {
709
+ VirtualConsole *vc = g_ptr_array_index(s->vcs, i);
710
gd_update_cursor(vc);
711
}
712
}
@@ -2114,9 +2117,10 @@ static void gd_vcs_init(GtkDisplayState *s, GSList *group,
2117
int i;
2118
2119
for (i = 0; i < nb_vcs; i++) {
2117
- VirtualConsole *vc = &s->vc[s->nb_vcs];
2118
- group = gd_vc_vte_init(s, vc, vcs[i], s->nb_vcs, group, view_menu);
2119
- s->nb_vcs++;
2120
+ VirtualConsole *vc = g_new0(VirtualConsole, 1);
2121
+ g_ptr_array_add(s->vcs, vc);
2122
+ group = gd_vc_vte_init(s, vc, vcs[i], s->vcs->len - 1,
2123
+ group, view_menu);
2124
}
2125
}
2126
#endif /* CONFIG_VTE */
@@ -2441,13 +2445,14 @@ static GtkWidget *gd_create_menu_view(GtkDisplayState *s, DisplayOptions *opts)
2445
2446
/* gfx */
2447
for (vc = 0;; vc++) {
2448
+ VirtualConsole *v;
2449
con = qemu_console_lookup_by_index(vc);
2450
if (!con) {
2451
break;
2452
}
2448
- group = gd_vc_gfx_init(s, &s->vc[vc], con,
2449
- vc, group, view_menu);
2450
- s->nb_vcs++;
2453
+ v = g_new0(VirtualConsole, 1);
2454
+ g_ptr_array_add(s->vcs, v);
2455
+ group = gd_vc_gfx_init(s, v, con, vc, group, view_menu);
2456
}
2457
2458
#if defined(CONFIG_VTE)
@@ -2505,6 +2510,64 @@ static void gd_create_menus(GtkDisplayState *s, DisplayOptions *opts)
2510
}
2511
2512
2513
+static void gd_vc_free(void *p)
2514
+{
2515
+ VirtualConsole *vc = p;
2516
+
2517
+ switch (vc->type) {
2518
+ case GD_VC_GFX:
2519
+ qemu_console_unregister_listener(&vc->gfx.dcl);
2520
+#if defined(CONFIG_OPENGL)
2521
+ if (display_opengl) {
2522
+ qemu_console_set_display_gl_ctx(vc->gfx.dcl.con, NULL);
2523
+ }
2524
+ if (vc->gfx.ectx) {
2525
+ eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
2526
+ vc->gfx.esurface, vc->gfx.ectx);
2527
+ } else if (gtk_use_gl_area) {
2528
+ gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
2529
+ }
2530
+ if (vc->gfx.gls) {
2531
+ surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds);
2532
+ qemu_gl_fini_shader(vc->gfx.gls);
2533
+ }
2534
+ egl_fb_destroy(&vc->gfx.guest_fb);
2535
+ egl_fb_destroy(&vc->gfx.win_fb);
2536
+ egl_fb_destroy(&vc->gfx.cursor_fb);
2537
+ if (vc->gfx.esurface) {
2538
+ eglDestroySurface(qemu_egl_display, vc->gfx.esurface);
2539
+ }
2540
+ if (vc->gfx.ectx) {
2541
+ eglDestroyContext(qemu_egl_display, vc->gfx.ectx);
2542
+ }
2543
+#endif
2544
+ qkbd_state_free(vc->gfx.kbd);
2545
+ if (vc->gfx.surface) {
2546
+ cairo_surface_destroy(vc->gfx.surface);
2547
+ }
2548
+ if (vc->gfx.convert) {
2549
+ pixman_image_unref(vc->gfx.convert);
2550
+ }
2551
+ break;
2552
+ case GD_VC_VTE:
2553
+#ifdef CONFIG_VTE
2554
+ fifo8_destroy(&vc->vte.out_fifo);
2555
+#endif
2556
+ break;
2557
+ }
2558
+
2559
+ if (vc->window) {
2560
+ gtk_widget_destroy(vc->window);
2561
+ } else if (vc->tab_item) {
2562
+ gtk_widget_destroy(vc->tab_item);
2563
+ }
2564
+ if (vc->menu_item) {
2565
+ gtk_widget_destroy(vc->menu_item);
2566
+ }
2567
+ g_free(vc->label);
2568
+ g_free(vc);
2569
+}
2570
+
2571
static GtkDisplayState *gtk_display_state;
2572
static gboolean gtkinit;
2573
@@ -2525,6 +2588,7 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts)
2588
assert(opts->type == DISPLAY_TYPE_GTK);
2589
s = g_malloc0(sizeof(*s));
2590
gtk_display_state = s;
2591
+ s->vcs = g_ptr_array_new_with_free_func(gd_vc_free);
2592
s->opts = opts;
2593
2594
theme = gtk_icon_theme_get_default();
@@ -2582,13 +2646,10 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts)
2646
2647
gtk_widget_show_all(s->window);
2648
2585
- for (idx = 0;; idx++) {
2586
- QemuConsole *con = qemu_console_lookup_by_index(idx);
2587
- if (!con) {
2588
- break;
2589
- }
2590
- if (s->vc[idx].type == GD_VC_GFX) {
2591
- gtk_widget_realize(s->vc[idx].gfx.drawing_area);
2649
+ for (idx = 0; idx < s->vcs->len; idx++) {
2650
+ VirtualConsole *v = g_ptr_array_index(s->vcs, idx);
2651
+ if (v->type == GD_VC_GFX) {
2652
+ gtk_widget_realize(v->gfx.drawing_area);
2653
}
2654
}
2655
@@ -2693,6 +2754,9 @@ static void gtk_display_cleanup(void)
2754
qemu_del_vm_change_state_handler(s->vmse);
2755
qemu_remove_mouse_mode_change_notifier(&s->mouse_mode_notifier);
2756
gd_clipboard_cleanup(s);
2757
+ g_signal_handlers_disconnect_by_func(s->notebook,
2758
+ G_CALLBACK(gd_change_page), s);
2759
+ g_clear_pointer(&s->vcs, g_ptr_array_unref);
2760
g_clear_pointer(&s->window, gtk_widget_destroy);
2761
g_clear_object(&s->null_cursor);
2762
g_clear_pointer(>k_display_state, g_free);