From ebd531c1c21a9f1ec8b3769fcd51244cf55f246c Mon Sep 17 00:00:00 2001
From: Marko Lindqvist <cazfi74@gmail.com>
Date: Wed, 9 Jul 2025 00:29:05 +0300
Subject: [PATCH 81/81] optiondlgs: Automatically apply options before saving

See RM #1587

Signed-off-by: Marko Lindqvist <cazfi74@gmail.com>
---
 client/gui-gtk-3.22/optiondlg.c |  4 +--
 client/gui-gtk-4.0/optiondlg.c  |  4 +--
 client/gui-gtk-5.0/optiondlg.c  |  4 +--
 client/gui-qt/optiondlg.cpp     |  4 +--
 client/options.c                | 50 +++++++++++++++++++++++++++++++--
 client/options.h                |  3 ++
 client/packhand.c               |  1 +
 7 files changed, 60 insertions(+), 10 deletions(-)

diff --git a/client/gui-gtk-3.22/optiondlg.c b/client/gui-gtk-3.22/optiondlg.c
index ddb15ca747..ad9753db35 100644
--- a/client/gui-gtk-3.22/optiondlg.c
+++ b/client/gui-gtk-3.22/optiondlg.c
@@ -117,8 +117,8 @@ static void option_dialog_reponse_callback(GtkDialog *dialog,
     option_dialog_foreach(pdialog, option_dialog_option_refresh);
     break;
   case RESPONSE_SAVE:
-    desired_settable_options_update();
-    options_save(NULL);
+    option_dialog_foreach(pdialog, option_dialog_option_apply);
+    queue_options_save(NULL);
     break;
   }
 }
diff --git a/client/gui-gtk-4.0/optiondlg.c b/client/gui-gtk-4.0/optiondlg.c
index 72544598bf..8ddb6bab7f 100644
--- a/client/gui-gtk-4.0/optiondlg.c
+++ b/client/gui-gtk-4.0/optiondlg.c
@@ -119,8 +119,8 @@ static void option_dialog_reponse_callback(GtkDialog *dialog,
     option_dialog_foreach(pdialog, option_dialog_option_refresh);
     break;
   case RESPONSE_SAVE:
-    desired_settable_options_update();
-    options_save(NULL);
+    option_dialog_foreach(pdialog, option_dialog_option_apply);
+    queue_options_save(NULL);
     break;
   }
 }
diff --git a/client/gui-gtk-5.0/optiondlg.c b/client/gui-gtk-5.0/optiondlg.c
index 3e3b75ff4f..31f65c10e3 100644
--- a/client/gui-gtk-5.0/optiondlg.c
+++ b/client/gui-gtk-5.0/optiondlg.c
@@ -119,8 +119,8 @@ static void option_dialog_reponse_callback(GtkDialog *dialog,
     option_dialog_foreach(pdialog, option_dialog_option_refresh);
     break;
   case RESPONSE_SAVE:
-    desired_settable_options_update();
-    options_save(NULL);
+    option_dialog_foreach(pdialog, option_dialog_option_apply);
+    queue_options_save(NULL);
     break;
   }
 }
diff --git a/client/gui-qt/optiondlg.cpp b/client/gui-qt/optiondlg.cpp
index 8a6eaacf13..dcf883a2d9 100644
--- a/client/gui-qt/optiondlg.cpp
+++ b/client/gui-qt/optiondlg.cpp
@@ -217,8 +217,8 @@ void option_dialog::apply_option(int response)
     close();
     break;
   case RESPONSE_SAVE:
-    desired_settable_options_update();
-    options_save(nullptr);
+    apply_options();
+    queue_options_save(nullptr);
     break;
   case RESPONSE_RESET:
     full_reset();
diff --git a/client/options.c b/client/options.c
index 99c89b6c1c..330996395a 100644
--- a/client/options.c
+++ b/client/options.c
@@ -448,6 +448,9 @@ struct client_options gui_options = {
 static bool options_fully_initialized = FALSE;
 
 static int sync_serial = 0;
+static int reply_serial = 0;
+static bool queue_save = FALSE;
+static option_save_log_callback queued_cb;
 
 static const struct strvec *get_mapimg_format_list(const struct option *poption);
 
@@ -752,7 +755,7 @@ struct option *option_next(const struct option *poption)
 }
 
 /************************************************************************//**
-  Set the option to its default value.  Returns TRUE if the option changed.
+  Set the option to its default value. Returns TRUE if the option changed.
 ****************************************************************************/
 bool option_reset(struct option *poption)
 {
@@ -5129,7 +5132,7 @@ static bool server_option_bool_def(const struct option *poption)
 }
 
 /************************************************************************//**
-  Set the value of this server option of type OT_BOOLEAN.  Returns TRUE if
+  Set the value of this server option of type OT_BOOLEAN. Returns TRUE if
   the value changed.
 ****************************************************************************/
 static bool server_option_bool_set(struct option *poption, bool val)
@@ -5142,6 +5145,8 @@ static bool server_option_bool_set(struct option *poption, bool val)
 
   send_chat_printf("/set %s %s", psoption->name,
                    val ? "enabled" : "disabled");
+  dsend_packet_sync_serial(&client.conn, ++sync_serial);
+
   return TRUE;
 }
 
@@ -5192,6 +5197,8 @@ static bool server_option_int_set(struct option *poption, int val)
   }
 
   send_chat_printf("/set %s %d", psoption->name, val);
+  dsend_packet_sync_serial(&client.conn, ++sync_serial);
+
   return TRUE;
 }
 
@@ -5234,6 +5241,8 @@ static bool server_option_str_set(struct option *poption, const char *str)
   }
 
   send_chat_printf("/set %s \"%s\"", psoption->name, str);
+  dsend_packet_sync_serial(&client.conn, ++sync_serial);
+
   return TRUE;
 }
 
@@ -5278,6 +5287,8 @@ static bool server_option_enum_set(struct option *poption, int val)
   }
 
   send_chat_printf("/set %s \"%s\"", psoption->name, name);
+  dsend_packet_sync_serial(&client.conn, ++sync_serial);
+
   return TRUE;
 }
 
@@ -5362,6 +5373,8 @@ static bool server_option_bitwise_set(struct option *poption, unsigned val)
   server_option_bitwise_support_base(psoption->bitwise.support_names, val,
                                      name, sizeof(name));
   send_chat_printf("/set %s \"%s\"", psoption->name, name);
+  dsend_packet_sync_serial(&client.conn, ++sync_serial);
+
   return TRUE;
 }
 
@@ -6427,6 +6440,37 @@ static void option_save_output_window_callback(enum log_level lvl,
   va_end(args);
 }
 
+/************************************************************************//**
+  Save the options as soon as they have been synced with the server.
+****************************************************************************/
+void queue_options_save(option_save_log_callback log_cb)
+{
+  if (reply_serial >= sync_serial) {
+    /* We've already got reply to the latest options sync request */
+    log_debug("Options save immediate (%d vs %d)", sync_serial, reply_serial);
+    desired_settable_options_update();
+    options_save(log_cb);
+  } else {
+    log_debug("Options save queued (%d vs %d)", sync_serial, reply_serial);
+    queue_save = TRUE;
+    queued_cb = log_cb;
+  }
+}
+
+/************************************************************************//**
+  Server has replied to some sync request
+****************************************************************************/
+void options_sync_reply(int serial)
+{
+  reply_serial = serial;
+
+  if (queue_save && reply_serial >= sync_serial) {
+    log_debug("Pop queued options saving.");
+    desired_settable_options_update();
+    options_save(queued_cb);
+  }
+}
+
 /************************************************************************//**
   Save all options.
 ****************************************************************************/
@@ -6437,6 +6481,8 @@ void options_save(option_save_log_callback log_cb)
   char dir_name[2048];
   int i;
 
+  queue_save = FALSE;
+
   if (log_cb == NULL) {
     /* Default callback */
     log_cb = option_save_output_window_callback;
diff --git a/client/options.h b/client/options.h
index 4b4e54bbd6..0c90613d9b 100644
--- a/client/options.h
+++ b/client/options.h
@@ -499,8 +499,11 @@ void options_free(void);
 void server_options_init(void);
 void server_options_free(void);
 void options_load(void);
+void queue_options_save(option_save_log_callback log_cb);
 void options_save(option_save_log_callback log_cb);
 
+void options_sync_reply(int serial);
+
 
 /* Option sets. */
 extern const struct option_set *client_optset;
diff --git a/client/packhand.c b/client/packhand.c
index 56e8e760cd..5ea2200550 100644
--- a/client/packhand.c
+++ b/client/packhand.c
@@ -5789,4 +5789,5 @@ void handle_city_update_counters(const struct packet_city_update_counters *packe
 **************************************************************************/
 void handle_sync_serial_reply(int serial)
 {
+  options_sync_reply(serial);
 }
-- 
2.47.2

