From 3f58911d96ad874519f18d136efff81c905945f1 Mon Sep 17 00:00:00 2001
From: Caeies <caeies@caeies.org>
Date: Mon, 31 Aug 2026 12:55:54 +0200
Subject: [PATCH 74/74] gtk4(x): Synchronize update_animation() with idle tick.

In GTK4 you should not g_idle_add() yourself during
idle loop execution.

See RM #2221
---
 client/gui-gtk-4.0/gui_main.c | 15 ++++++++++++---
 client/gui-gtk-4.0/gui_main.h |  1 -
 client/gui-gtk-4.0/pages.c    |  1 -
 client/gui-gtk-5.0/gui_main.c | 15 ++++++++++++---
 client/gui-gtk-5.0/gui_main.h |  1 -
 client/gui-gtk-5.0/pages.c    |  1 -
 6 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/client/gui-gtk-4.0/gui_main.c b/client/gui-gtk-4.0/gui_main.c
index 0913e68d22..237725c640 100644
--- a/client/gui-gtk-4.0/gui_main.c
+++ b/client/gui-gtk-4.0/gui_main.c
@@ -223,6 +223,10 @@ static void free_unit_table(void);
 
 static void adjust_default_options(void);
 
+static gboolean animation_tick_cb(GtkWidget *widget,
+                                  GdkFrameClock *frame_clock,
+                                  gpointer user_data);
+
 static float zoom_steps_custom[] = {
   -1.0, 0.13, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 2.0, 2.5, 3.0, 4.0, -1.0
 };
@@ -1479,6 +1483,9 @@ static void setup_widgets(void)
   g_signal_connect(map_canvas, "resize",
                    G_CALLBACK(map_canvas_resize), NULL);
 
+  /* Synchronize animation updates with the tick (improve performances) */
+  gtk_widget_add_tick_callback(map_canvas, animation_tick_cb, NULL, NULL);
+
   mc_controller = gtk_event_controller_key_new();
   g_signal_connect(mc_controller, "key-pressed",
                    G_CALLBACK(toplevel_key_press_handler), NULL);
@@ -2395,14 +2402,16 @@ void add_idle_callback(void (callback)(void *), void *data)
 }
 
 /**********************************************************************//**
-  Add idle callback for updating animations.
+  Update animations if needed on the current GUI tick.
 **************************************************************************/
-void animation_idle_cb(void *data)
+static gboolean animation_tick_cb(GtkWidget *widget,
+                                  GdkFrameClock *frame_clock,
+                                  gpointer user_data)
 {
   if (get_current_client_page() == PAGE_GAME) {
     update_animation();
-    add_idle_callback(animation_idle_cb, NULL);
   }
+  return G_SOURCE_CONTINUE; /* keep animation call back running */
 }
 
 /**********************************************************************//**
diff --git a/client/gui-gtk-4.0/gui_main.h b/client/gui-gtk-4.0/gui_main.h
index fff13e12ec..80013afb39 100644
--- a/client/gui-gtk-4.0/gui_main.h
+++ b/client/gui-gtk-4.0/gui_main.h
@@ -37,7 +37,6 @@
 #define GUI_GTK_DEFAULT_THEME_NAME FC_GTK4_DEFAULT_THEME_NAME
 
 void main_message_area_resize(void *data);
-void animation_idle_cb(void *data);
 
 /* Network string charset conversion */
 gchar *ntoh_str(const gchar *netstr);
diff --git a/client/gui-gtk-4.0/pages.c b/client/gui-gtk-4.0/pages.c
index 18c5b8e0a0..c371fc8e19 100644
--- a/client/gui-gtk-4.0/pages.c
+++ b/client/gui-gtk-4.0/pages.c
@@ -3605,7 +3605,6 @@ void real_set_client_page(enum client_pages new_page)
     center_on_something();
     mapview_thaw();
     add_idle_callback(main_message_area_resize, NULL);
-    add_idle_callback(animation_idle_cb, NULL);
     break;
   case PAGE_NETWORK:
     update_network_lists();
diff --git a/client/gui-gtk-5.0/gui_main.c b/client/gui-gtk-5.0/gui_main.c
index 67c77e744f..b30ab189a5 100644
--- a/client/gui-gtk-5.0/gui_main.c
+++ b/client/gui-gtk-5.0/gui_main.c
@@ -224,6 +224,10 @@ static void free_unit_table(void);
 
 static void adjust_default_options(void);
 
+static gboolean animation_tick_cb(GtkWidget *widget,
+                                  GdkFrameClock *frame_clock,
+                                  gpointer user_data);
+
 static float zoom_steps_custom[] = {
   -1.0, 0.13, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 2.0, 2.5, 3.0, 4.0, -1.0
 };
@@ -1480,6 +1484,9 @@ static void setup_widgets(void)
   g_signal_connect(map_canvas, "resize",
                    G_CALLBACK(map_canvas_resize), NULL);
 
+  /* Synchronize animation updates with the tick (improve performances) */
+  gtk_widget_add_tick_callback(map_canvas, animation_tick_cb, NULL, NULL);
+
   mc_controller = gtk_event_controller_key_new();
   g_signal_connect(mc_controller, "key-pressed",
                    G_CALLBACK(toplevel_key_press_handler), NULL);
@@ -2452,14 +2459,16 @@ void add_idle_callback(void (callback)(void *), void *data)
 }
 
 /**********************************************************************//**
-  Add idle callback for updating animations.
+  Update animations if needed on the current GUI tick.
 **************************************************************************/
-void animation_idle_cb(void *data)
+static gboolean animation_tick_cb(GtkWidget *widget,
+                                  GdkFrameClock *frame_clock,
+                                  gpointer user_data)
 {
   if (get_current_client_page() == PAGE_GAME) {
     update_animation();
-    add_idle_callback(animation_idle_cb, NULL);
   }
+  return G_SOURCE_CONTINUE; /* keep animation call back running */
 }
 
 /**********************************************************************//**
diff --git a/client/gui-gtk-5.0/gui_main.h b/client/gui-gtk-5.0/gui_main.h
index 9348f7b641..635646ebad 100644
--- a/client/gui-gtk-5.0/gui_main.h
+++ b/client/gui-gtk-5.0/gui_main.h
@@ -37,7 +37,6 @@
 #define GUI_GTK_DEFAULT_THEME_NAME FC_GTK5_DEFAULT_THEME_NAME
 
 void main_message_area_resize(void *data);
-void animation_idle_cb(void *data);
 
 /* Network string charset conversion */
 gchar *ntoh_str(const gchar *netstr);
diff --git a/client/gui-gtk-5.0/pages.c b/client/gui-gtk-5.0/pages.c
index 44f3878552..cd4303f8e0 100644
--- a/client/gui-gtk-5.0/pages.c
+++ b/client/gui-gtk-5.0/pages.c
@@ -4060,7 +4060,6 @@ void real_set_client_page(enum client_pages new_page)
     center_on_something();
     mapview_thaw();
     add_idle_callback(main_message_area_resize, NULL);
-    add_idle_callback(animation_idle_cb, NULL);
     break;
   case PAGE_NETWORK:
     update_network_lists();
-- 
2.53.0

