@samitouri / QOSamiQemu / commits / b09e45f77a

ui/gtk: implement display cleanup

Add gtk_display_cleanup() to properly tear down GTK display state: remove console and mouse notifiers, unregister clipboard peer, destroy the main window and virtual consoles. 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-22-4656aec3398d@redhat.com>

Marc-André Lureau committed Jun 23, 2026 at 11:44 UTC b09e45f77a01919e7ead3c053c1647f66a1776d9
3 files changed +36 -1
include/ui/gtk.h
+2
@@ -140,6 +140,7 @@ struct GtkDisplayState {
140
141 GdkCursor *null_cursor;
142 Notifier mouse_mode_notifier;
143 + VMChangeStateEntry *vmse;
144 gboolean free_scale;
145 gboolean keep_aspect_ratio;
146
@@ -225,6 +226,7 @@ int gd_gl_area_make_current(DisplayGLCtx *dgc,
226
227 /* gtk-clipboard.c */
228 void gd_clipboard_init(GtkDisplayState *gd);
229 +void gd_clipboard_cleanup(GtkDisplayState *gd);
230
231 void gd_update_scale(VirtualConsole *vc, int ww, int wh, int fbw, int fbh);
232
ui/gtk-clipboard.c
+15
@@ -235,3 +235,18 @@ void gd_clipboard_init(GtkDisplayState *gd)
235 g_signal_connect(gd->gtkcb[QEMU_CLIPBOARD_SELECTION_SECONDARY],
236 "owner-change", G_CALLBACK(gd_owner_change), gd);
237 }
238 +
239 +void gd_clipboard_cleanup(GtkDisplayState *gd)
240 +{
241 + if (!gd->cbpeer.name) {
242 + return;
243 + }
244 + qemu_clipboard_peer_unregister(&gd->cbpeer);
245 + g_signal_handlers_disconnect_by_data(
246 + gd->gtkcb[QEMU_CLIPBOARD_SELECTION_CLIPBOARD], gd);
247 + g_signal_handlers_disconnect_by_data(
248 + gd->gtkcb[QEMU_CLIPBOARD_SELECTION_PRIMARY], gd);
249 + g_signal_handlers_disconnect_by_data(
250 + gd->gtkcb[QEMU_CLIPBOARD_SELECTION_SECONDARY], gd);
251 + gd->cbpeer.name = NULL;
252 +}
ui/gtk.c
+19 -1
@@ -2505,6 +2505,7 @@ static void gd_create_menus(GtkDisplayState *s, DisplayOptions *opts)
2505 }
2506
2507
2508 +static GtkDisplayState *gtk_display_state;
2509 static gboolean gtkinit;
2510
2511 static void gtk_display_init(DisplayState *ds, DisplayOptions *opts)
@@ -2523,6 +2524,7 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts)
2524 }
2525 assert(opts->type == DISPLAY_TYPE_GTK);
2526 s = g_malloc0(sizeof(*s));
2527 + gtk_display_state = s;
2528 s->opts = opts;
2529
2530 theme = gtk_icon_theme_get_default();
@@ -2560,7 +2562,7 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts)
2562
2563 s->mouse_mode_notifier.notify = gd_mouse_mode_change;
2564 qemu_add_mouse_mode_change_notifier(&s->mouse_mode_notifier);
2563 - qemu_add_vm_change_state_handler(gd_change_runstate, s);
2565 + s->vmse = qemu_add_vm_change_state_handler(gd_change_runstate, s);
2566
2567 gtk_window_set_icon_name(GTK_WINDOW(s->window), "qemu");
2568
@@ -2681,10 +2683,26 @@ static void early_gtk_display_init(DisplayOptions *opts)
2683 #endif
2684 }
2685
2686 +static void gtk_display_cleanup(void)
2687 +{
2688 + GtkDisplayState *s = gtk_display_state;
2689 +
2690 + if (!s) {
2691 + return;
2692 + }
2693 + qemu_del_vm_change_state_handler(s->vmse);
2694 + qemu_remove_mouse_mode_change_notifier(&s->mouse_mode_notifier);
2695 + gd_clipboard_cleanup(s);
2696 + g_clear_pointer(&s->window, gtk_widget_destroy);
2697 + g_clear_object(&s->null_cursor);
2698 + g_clear_pointer(&gtk_display_state, g_free);
2699 +}
2700 +
2701 static QemuDisplay qemu_display_gtk = {
2702 .type = DISPLAY_TYPE_GTK,
2703 .early_init = early_gtk_display_init,
2704 .init = gtk_display_init,
2705 + .cleanup = gtk_display_cleanup,
2706 .vc = "vc",
2707 };
2708