So this has nailed me twice and maybe this time I’ll remember. If you have a toplevel (GtkWindow, GtkDialog, etc) in a GtkBuilder file, and you load that file into a GtkBuilder object, you need to remember to explicitly call gtk_widget_destroy() on it. GtkBuilder will sink the initial GTK floating ref for you, but that means you now have widget with 2 references (object creation and the ref sink) and getting rid of the GtkBuilder will only remove one of those references for you. You then need to remember to call gtk_widget_destroy() to get rid of the other one. Not g_object_unref() apparently, as that’ll cause segfaults somewhere later on during widget destruction when something tries to disconnect some signal handlers somewhere, but gtk_widget_destroy(). This also removes the toplevels from GTK’s “toplevel_list” which, if you’re not careful and forget to destroy it, can lead to segfaults later when GTK tries to issue grabs when you’re scrolling. Those are always entertaining to track down. And when I say entertaining I don’t actually mean it.
GtkBuilder even has documentation about this:
For toplevel windows constructed by a builder, it is the responsibility of the user to call gtk_widget_destroy() to get rid of them and all the widgets they contain.
but somehow I keep forgetting. And then I waste and hour figuring out WTF is going wrong.