From f4cc057882bc1c5864812060e2b9a1ca4ce3ec01 Mon Sep 17 00:00:00 2001
From: Marko Lindqvist <cazfi74@gmail.com>
Date: Wed, 14 Oct 2026 19:26:41 +0300
Subject: [PATCH 80/80] gtk4(x): Fix diplodlg closing memory handling

- Revert RM #2306.
- Move any access to another dialog's content
  from gui_dialog_destroy_handler() to happen already
  gui_dialog_destroy()

See RM #2371

Signed-off-by: Marko Lindqvist <cazfi74@gmail.com>
---
 client/gui-gtk-4.0/diplodlg.c  | 18 +++++++++++-------
 client/gui-gtk-4.0/gui_stuff.c | 17 ++++++-----------
 client/gui-gtk-5.0/diplodlg.c  | 18 +++++++++++-------
 client/gui-gtk-5.0/gui_stuff.c | 17 ++++++-----------
 4 files changed, 34 insertions(+), 36 deletions(-)

diff --git a/client/gui-gtk-4.0/diplodlg.c b/client/gui-gtk-4.0/diplodlg.c
index bbe2b0dea1..dbc365dd38 100644
--- a/client/gui-gtk-4.0/diplodlg.c
+++ b/client/gui-gtk-4.0/diplodlg.c
@@ -240,6 +240,7 @@ static void popup_diplomacy_dialog(struct treaty *ptreaty, struct player *they,
     /* We have to raise the diplomacy meeting tab as well as the selected
      * meeting. */
     fc_assert_ret(dipl_main != NULL);
+
     gui_dialog_raise(dipl_main->dialog);
     gui_dialog_raise(pdialog->dialog);
 
@@ -690,14 +691,16 @@ static void diplomacy_main_response(struct gui_dialog *dlg, int response,
 }
 
 /************************************************************************//**
-  Remove diplomacy dialog from use.
+  Destroy diplomacy dialog
 ****************************************************************************/
-static void diplomacy_remove(struct Diplomacy_dialog *pdialog)
+static void diplomacy_destroy(struct Diplomacy_dialog *pdialog)
 {
-  /* Dialog destroy callbacks will take care of freeing everything
-   * related to the pdialog->dialog.
-   * Here we just take the dialog out of use. */
-
+  if (NULL != pdialog->dialog) {
+    /* pdialog->dialog may be NULL if the tab has been destroyed
+     * by an other way. */
+    gui_dialog_destroy(pdialog->dialog);
+    pdialog->dialog = NULL;
+  }
   dialog_list_remove(dialog_list, pdialog);
 
   if (dialog_list) {
@@ -729,6 +732,7 @@ static void diplomacy_response(struct gui_dialog *dlg, int response,
   struct Diplomacy_dialog *pdialog = NULL;
 
   fc_assert_ret(data);
+
   pdialog = (struct Diplomacy_dialog *)data;
 
   switch (response) {
@@ -1277,7 +1281,7 @@ static void diplomacy_dialog_shared_tiles_callback(GSimpleAction *action,
 ****************************************************************************/
 void close_diplomacy_dialog(struct Diplomacy_dialog *pdialog)
 {
-  diplomacy_remove(pdialog);
+  diplomacy_destroy(pdialog);
 }
 
 /************************************************************************//**
diff --git a/client/gui-gtk-4.0/gui_stuff.c b/client/gui-gtk-4.0/gui_stuff.c
index a562f8b524..6e2b4036f2 100644
--- a/client/gui-gtk-4.0/gui_stuff.c
+++ b/client/gui-gtk-4.0/gui_stuff.c
@@ -307,19 +307,8 @@ static void gui_dialog_destroyed(struct gui_dialog *dlg, int response,
 **************************************************************************/
 static void gui_dialog_destroy_handler(GtkWidget *w, struct gui_dialog *dlg)
 {
-  if (dlg->type == GUI_DIALOG_TAB) {
-    GtkWidget *notebook = dlg->v.tab.notebook;
-    gulong handler_id = dlg->v.tab.handler_id;
-
-    g_signal_handler_disconnect(notebook, handler_id);
-  }
-
   g_object_unref(dlg->gui_button);
 
-  if (*(dlg->source)) {
-    *(dlg->source) = NULL;
-  }
-
   dialog_list = g_list_remove(dialog_list, dlg);
 
   /* Raise the return dialog set by gui_dialog_set_return_dialog() */
@@ -894,9 +883,15 @@ void gui_dialog_destroy(struct gui_dialog *dlg)
 
       n = gtk_notebook_page_num(GTK_NOTEBOOK(dlg->v.tab.notebook), dlg->grid);
       gtk_notebook_remove_page(GTK_NOTEBOOK(dlg->v.tab.notebook), n);
+      g_signal_handler_disconnect(GTK_NOTEBOOK(dlg->v.tab.notebook),
+                                  dlg->v.tab.handler_id);
     }
     break;
   }
+
+  if (*(dlg->source)) {
+    *(dlg->source) = NULL;
+  }
 }
 
 /**********************************************************************//**
diff --git a/client/gui-gtk-5.0/diplodlg.c b/client/gui-gtk-5.0/diplodlg.c
index de8aee612f..8135662dae 100644
--- a/client/gui-gtk-5.0/diplodlg.c
+++ b/client/gui-gtk-5.0/diplodlg.c
@@ -289,6 +289,7 @@ static void popup_diplomacy_dialog(struct treaty *ptreaty, struct player *they,
     /* We have to raise the diplomacy meeting tab as well as the selected
      * meeting. */
     fc_assert_ret(dipl_main != NULL);
+
     gui_dialog_raise(dipl_main->dialog);
     gui_dialog_raise(pdialog->dialog);
 
@@ -739,14 +740,16 @@ static void diplomacy_main_response(struct gui_dialog *dlg, int response,
 }
 
 /************************************************************************//**
-  Remove diplomacy dialog from use.
+  Destroy diplomacy dialog
 ****************************************************************************/
-static void diplomacy_remove(struct Diplomacy_dialog *pdialog)
+static void diplomacy_destroy(struct Diplomacy_dialog *pdialog)
 {
-  /* Dialog destroy callbacks will take care of freeing everything
-   * related to the pdialog->dialog.
-   * Here we just take the dialog out of use. */
-
+  if (NULL != pdialog->dialog) {
+    /* pdialog->dialog may be NULL if the tab has been destroyed
+     * by an other way. */
+    gui_dialog_destroy(pdialog->dialog);
+    pdialog->dialog = NULL;
+  }
   dialog_list_remove(dialog_list, pdialog);
 
   if (dialog_list) {
@@ -778,6 +781,7 @@ static void diplomacy_response(struct gui_dialog *dlg, int response,
   struct Diplomacy_dialog *pdialog = NULL;
 
   fc_assert_ret(data);
+
   pdialog = (struct Diplomacy_dialog *)data;
 
   switch (response) {
@@ -1358,7 +1362,7 @@ static void diplomacy_dialog_shared_tiles_callback(GSimpleAction *action,
 ****************************************************************************/
 void close_diplomacy_dialog(struct Diplomacy_dialog *pdialog)
 {
-  diplomacy_remove(pdialog);
+  diplomacy_destroy(pdialog);
 }
 
 /************************************************************************//**
diff --git a/client/gui-gtk-5.0/gui_stuff.c b/client/gui-gtk-5.0/gui_stuff.c
index ff1db49085..09d34f613b 100644
--- a/client/gui-gtk-5.0/gui_stuff.c
+++ b/client/gui-gtk-5.0/gui_stuff.c
@@ -308,19 +308,8 @@ static void gui_dialog_destroyed(struct gui_dialog *dlg, int response,
 **************************************************************************/
 static void gui_dialog_destroy_handler(GtkWidget *w, struct gui_dialog *dlg)
 {
-  if (dlg->type == GUI_DIALOG_TAB) {
-    GtkWidget *notebook = dlg->v.tab.notebook;
-    gulong handler_id = dlg->v.tab.handler_id;
-
-    g_signal_handler_disconnect(notebook, handler_id);
-  }
-
   g_object_unref(dlg->gui_button);
 
-  if (*(dlg->source)) {
-    *(dlg->source) = NULL;
-  }
-
   dialog_list = g_list_remove(dialog_list, dlg);
 
   /* Raise the return dialog set by gui_dialog_set_return_dialog() */
@@ -895,9 +884,15 @@ void gui_dialog_destroy(struct gui_dialog *dlg)
 
       n = gtk_notebook_page_num(GTK_NOTEBOOK(dlg->v.tab.notebook), dlg->grid);
       gtk_notebook_remove_page(GTK_NOTEBOOK(dlg->v.tab.notebook), n);
+      g_signal_handler_disconnect(GTK_NOTEBOOK(dlg->v.tab.notebook),
+                                  dlg->v.tab.handler_id);
     }
     break;
   }
+
+  if (*(dlg->source)) {
+    *(dlg->source) = NULL;
+  }
 }
 
 /**********************************************************************//**
-- 
2.53.0

