From 7e7eb716acfae19d98bd412c0e71cc2d8047d928 Mon Sep 17 00:00:00 2001
From: Marko Lindqvist <cazfi74@gmail.com>
Date: Sat, 16 Nov 2024 02:52:07 +0200
Subject: [PATCH 84/84] gtk4x: Add implemention for pages.c host list as
 GListStore

Only add new implementation. Keep the old implementation still
the active one. Mark, by variable names, old implementation
as deprecated.

See RM #1125

Signed-off-by: Marko Lindqvist <cazfi74@gmail.com>
---
 client/gui-gtk-5.0/pages.c | 318 ++++++++++++++++++++++++++++++-------
 1 file changed, 265 insertions(+), 53 deletions(-)

diff --git a/client/gui-gtk-5.0/pages.c b/client/gui-gtk-5.0/pages.c
index 32030ae8b7..f116c9551c 100644
--- a/client/gui-gtk-5.0/pages.c
+++ b/client/gui-gtk-5.0/pages.c
@@ -67,13 +67,15 @@ static GtkWidget *scenario_authors;
 static GtkWidget *scenario_filename;
 static GtkWidget *scenario_version;
 
-static GtkListStore *load_store, *scenario_store, *meta_store, *lan_store;
+static GtkListStore *load_store, *scenario_store, *meta_store_depr, *lan_store_depr;
+static GListStore *lan_store, *meta_store;
 
 static GtkListStore *server_playerlist_store;
 static GtkWidget *server_playerlist_view;
 
 static GtkTreeSelection *load_selection, *scenario_selection;
-static GtkTreeSelection *meta_selection, *lan_selection;
+static GtkTreeSelection *meta_selection_depr, *lan_selection_depr;
+static GtkSingleSelection *meta_selection, *lan_selection;
 
 /* This is the current page. Invalid value at start, to be sure that it won't
  * be caught through a switch() statement. */
@@ -206,12 +208,30 @@ struct _FcSaveClass
 
 G_DEFINE_TYPE(FcSaveRow, fc_save_row, G_TYPE_OBJECT)
 
+/**********************************************************************//**
+  Finalizing method for FcHostRow class
+**************************************************************************/
+static void fc_host_row_finalize(GObject *gobject)
+{
+  FcHostRow *row = FC_HOST_ROW(gobject);
+
+  if (row->humans != nullptr) {
+    free(row->humans);
+    row->humans = nullptr;
+  }
+
+  G_OBJECT_CLASS(fc_host_row_parent_class)->finalize(gobject);
+}
+
 /**********************************************************************//**
   Initialization method for FcHostRow class
 **************************************************************************/
 static void
 fc_host_row_class_init(FcHostRowClass *klass)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+  object_class->finalize = fc_host_row_finalize;
 }
 
 /**********************************************************************//**
@@ -220,12 +240,12 @@ fc_host_row_class_init(FcHostRowClass *klass)
 static void
 fc_host_row_init(FcHostRow *self)
 {
+  self->humans = nullptr;
 }
 
 /**********************************************************************//**
   FcHostRow creation method
 **************************************************************************/
-#if 0
 static FcHostRow *fc_host_row_new(void)
 {
   FcHostRow *result;
@@ -234,7 +254,6 @@ static FcHostRow *fc_host_row_new(void)
 
   return result;
 }
-#endif
 
 /**********************************************************************//**
   Initialization method for FcPlrRow class
@@ -974,31 +993,38 @@ static GtkWidget *network_confirm_password_label, *network_confirm_password;
 static void update_server_list(enum server_scan_type sstype,
                                const struct server_list *list)
 {
-  GtkTreeSelection *sel = NULL;
+  GtkTreeSelection *sel_depr = nullptr;
+  GListStore *store = nullptr;
   GtkTreeView *view;
   GtkTreeIter it;
-  GtkListStore *store;
+  GtkListStore *store_depr;
   const gchar *host, *portstr;
   int port;
 
   switch (sstype) {
   case SERVER_SCAN_LOCAL:
-    sel = lan_selection;
+    sel_depr = lan_selection_depr;
+    store = G_LIST_STORE(gtk_single_selection_get_model(lan_selection));
     break;
   case SERVER_SCAN_GLOBAL:
-    sel = meta_selection;
+    sel_depr = meta_selection_depr;
+    store = G_LIST_STORE(gtk_single_selection_get_model(meta_selection));
     break;
   default:
     break;
   }
 
-  if (!sel) {
+  if (sel_depr == nullptr) {
     return;
   }
 
-  view = gtk_tree_selection_get_tree_view(sel);
-  store = GTK_LIST_STORE(gtk_tree_view_get_model(view));
-  gtk_list_store_clear(store);
+  if (store == nullptr) {
+    return;
+  }
+
+  view = gtk_tree_selection_get_tree_view(sel_depr);
+  store_depr = GTK_LIST_STORE(gtk_tree_view_get_model(view));
+  gtk_list_store_clear(store_depr);
 
   if (!list) {
     return;
@@ -1016,8 +1042,8 @@ static void update_server_list(enum server_scan_type sstype,
     } else {
       sz_strlcpy(buf, _("Unknown"));
     }
-    gtk_list_store_append(store, &it);
-    gtk_list_store_set(store, &it,
+    gtk_list_store_append(store_depr, &it);
+    gtk_list_store_set(store_depr, &it,
                        0, pserver->host,
                        1, pserver->port,
                        2, pserver->version,
@@ -1027,8 +1053,21 @@ static void update_server_list(enum server_scan_type sstype,
                        6, pserver->message,
                        -1);
     if (strcmp(host, pserver->host) == 0 && port == pserver->port) {
-      gtk_tree_selection_select_iter(sel, &it);
+      gtk_tree_selection_select_iter(sel_depr, &it);
     }
+
+    FcHostRow *row = fc_host_row_new();
+
+    row->host = pserver->host;
+    row->port = pserver->port;
+    row->version = pserver->version;
+    row->state = _(pserver->state);
+    row->nplayers = pserver->nplayers;
+    row->humans = fc_strdup(buf);
+    row->message = pserver->message;
+
+    g_list_store_append(store, row);
+    g_object_unref(row);
   } server_list_iterate_end;
 }
 
@@ -1371,10 +1410,10 @@ static void connect_callback(GtkWidget *w, gpointer data)
 /**********************************************************************//**
   Connect on list item double-click.
 **************************************************************************/
-static void network_activate_callback(GtkTreeView *view,
-                                      GtkTreePath *arg1,
-                                      GtkTreeViewColumn *arg2,
-                                      gpointer data)
+static void network_activate_callback_depr(GtkTreeView *view,
+                                           GtkTreePath *arg1,
+                                           GtkTreeViewColumn *arg2,
+                                           gpointer data)
 {
   connect_callback(NULL, data);
 }
@@ -1412,7 +1451,7 @@ static void update_server_playerlist(const struct server *pserver)
 /**********************************************************************//**
   Sets the host, port and player list of the selected server.
 **************************************************************************/
-static void network_list_callback(GtkTreeSelection *select, gpointer data)
+static void network_list_callback_depr(GtkTreeSelection *select, gpointer data)
 {
   GtkTreeModel *model;
   GtkTreeIter it;
@@ -1425,7 +1464,7 @@ static void network_list_callback(GtkTreeSelection *select, gpointer data)
     return;
   }
 
-  if (select == meta_selection) {
+  if (select == meta_selection_depr) {
     GtkTreePath *path;
     struct srv_list *srvrs;
 
@@ -1455,6 +1494,43 @@ static void network_list_callback(GtkTreeSelection *select, gpointer data)
   gtk_entry_buffer_set_text(gtk_entry_get_buffer(GTK_ENTRY(network_port)), portstr, -1);
 }
 
+/**********************************************************************//**
+  Sets the host, port and player list of the selected server.
+**************************************************************************/
+static void network_list_callback(GtkSelectionModel *self,
+                                  guint position, guint n_items,
+                                  gpointer data)
+{
+  char portstr[32];
+  const struct server *pserver = nullptr;
+  int sel_index = gtk_single_selection_get_selected(GTK_SINGLE_SELECTION(self));
+  FcHostRow *row = gtk_single_selection_get_selected_item(GTK_SINGLE_SELECTION(self));
+
+  if (self == GTK_SELECTION_MODEL(meta_selection)) {
+    struct srv_list *srvrs;
+
+    srvrs = server_scan_get_list(meta_scan.scan);
+    if (!holding_srv_list_mutex) {
+      /* We are not yet inside mutex protected block */
+      fc_mutex_allocate(&srvrs->mutex);
+    }
+    if (srvrs->servers != nullptr && sel_index >= 0) {
+      pserver = server_list_get(srvrs->servers, sel_index);
+    }
+    if (!holding_srv_list_mutex) {
+      /* We are not yet inside mutex protected block */
+      fc_mutex_release(&srvrs->mutex);
+    }
+  }
+  update_server_playerlist(pserver);
+
+  gtk_entry_buffer_set_text(gtk_entry_get_buffer(GTK_ENTRY(network_host)),
+                            row->host, -1);
+  fc_snprintf(portstr, sizeof(portstr), "%d", row->port);
+  gtk_entry_buffer_set_text(gtk_entry_get_buffer(GTK_ENTRY(network_port)),
+                            portstr, -1);
+}
+
 /**********************************************************************//**
   Update the network page.
 **************************************************************************/
@@ -1462,8 +1538,8 @@ static void update_network_page(void)
 {
   char buf[256];
 
-  gtk_tree_selection_unselect_all(lan_selection);
-  gtk_tree_selection_unselect_all(meta_selection);
+  gtk_tree_selection_unselect_all(lan_selection_depr);
+  gtk_tree_selection_unselect_all(meta_selection_depr);
 
   gtk_entry_buffer_set_text(gtk_entry_get_buffer(GTK_ENTRY(network_login)), user_name, -1);
   gtk_entry_buffer_set_text(gtk_entry_get_buffer(GTK_ENTRY(network_host)), server_host, -1);
@@ -1566,10 +1642,12 @@ GtkWidget *create_network_page(void)
 {
   GtkWidget *box, *sbox, *bbox, *hbox, *notebook;
   GtkWidget *button, *label, *view, *sw, *table;
-  GtkTreeSelection *selection;
+  GtkTreeSelection *selection_depr;
   GtkListStore *store;
   GtkEventController *controller;
   GtkListItemFactory *factory;
+  GtkWidget *list;
+  GtkColumnViewColumn *column;
 
   box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
   gtk_widget_set_margin_start(box, 4);
@@ -1581,13 +1659,17 @@ GtkWidget *create_network_page(void)
   gtk_box_append(GTK_BOX(box), notebook);
 
   /* LAN pane. */
-  lan_store = gtk_list_store_new(7, G_TYPE_STRING, /* host */
-                                 G_TYPE_INT,       /* port */
-                                 G_TYPE_STRING,    /* version */
-                                 G_TYPE_STRING,    /* state */
-                                 G_TYPE_INT,       /* nplayers */
-                                 G_TYPE_STRING,    /* humans */
-                                 G_TYPE_STRING);   /* message */
+  lan_store_depr = gtk_list_store_new(7, G_TYPE_STRING, /* host */
+                                      G_TYPE_INT,       /* port */
+                                      G_TYPE_STRING,    /* version */
+                                      G_TYPE_STRING,    /* state */
+                                      G_TYPE_INT,       /* nplayers */
+                                      G_TYPE_STRING,    /* humans */
+                                      G_TYPE_STRING);   /* message */
+
+  lan_store = g_list_store_new(FC_TYPE_HOST_ROW);
+  lan_selection = gtk_single_selection_new(G_LIST_MODEL(lan_store));
+  list = gtk_column_view_new(GTK_SELECTION_MODEL(lan_selection));
 
   factory = gtk_signal_list_item_factory_new();
   g_signal_connect(factory, "bind", G_CALLBACK(host_factory_bind),
@@ -1595,15 +1677,72 @@ GtkWidget *create_network_page(void)
   g_signal_connect(factory, "setup", G_CALLBACK(host_factory_setup),
                    nullptr);
 
-  view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(lan_store));
+  column = gtk_column_view_column_new(_("Host"), factory);
+  gtk_column_view_append_column(GTK_COLUMN_VIEW(list), column);
+
+  factory = gtk_signal_list_item_factory_new();
+  g_signal_connect(factory, "bind", G_CALLBACK(host_factory_bind),
+                   GINT_TO_POINTER(host_row_port));
+  g_signal_connect(factory, "setup", G_CALLBACK(host_factory_setup),
+                   nullptr);
+
+  column = gtk_column_view_column_new(_("Port"), factory);
+  gtk_column_view_append_column(GTK_COLUMN_VIEW(list), column);
+
+  factory = gtk_signal_list_item_factory_new();
+  g_signal_connect(factory, "bind", G_CALLBACK(host_factory_bind),
+                   GINT_TO_POINTER(host_row_version));
+  g_signal_connect(factory, "setup", G_CALLBACK(host_factory_setup),
+                   nullptr);
+
+  column = gtk_column_view_column_new(_("Version"), factory);
+  gtk_column_view_append_column(GTK_COLUMN_VIEW(list), column);
+
+  factory = gtk_signal_list_item_factory_new();
+  g_signal_connect(factory, "bind", G_CALLBACK(host_factory_bind),
+                   GINT_TO_POINTER(host_row_state));
+  g_signal_connect(factory, "setup", G_CALLBACK(host_factory_setup),
+                   nullptr);
+
+  column = gtk_column_view_column_new(_("Status"), factory);
+  gtk_column_view_append_column(GTK_COLUMN_VIEW(list), column);
+
+  factory = gtk_signal_list_item_factory_new();
+  g_signal_connect(factory, "bind", G_CALLBACK(host_factory_bind),
+                   GINT_TO_POINTER(host_row_nplayers));
+  g_signal_connect(factory, "setup", G_CALLBACK(host_factory_setup),
+                   nullptr);
+
+  column = gtk_column_view_column_new(_("Players"), factory);
+  gtk_column_view_append_column(GTK_COLUMN_VIEW(list), column);
+
+  factory = gtk_signal_list_item_factory_new();
+  g_signal_connect(factory, "bind", G_CALLBACK(host_factory_bind),
+                   GINT_TO_POINTER(host_row_humans));
+  g_signal_connect(factory, "setup", G_CALLBACK(host_factory_setup),
+                   nullptr);
+
+  column = gtk_column_view_column_new(_("Humans"), factory);
+  gtk_column_view_append_column(GTK_COLUMN_VIEW(list), column);
+
+  factory = gtk_signal_list_item_factory_new();
+  g_signal_connect(factory, "bind", G_CALLBACK(host_factory_bind),
+                   GINT_TO_POINTER(host_row_message));
+  g_signal_connect(factory, "setup", G_CALLBACK(host_factory_setup),
+                   nullptr);
+
+  column = gtk_column_view_column_new(_("Comment"), factory);
+  gtk_column_view_append_column(GTK_COLUMN_VIEW(list), column);
+
+  view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(lan_store_depr));
   gtk_widget_set_hexpand(view, TRUE);
   gtk_widget_set_vexpand(view, TRUE);
-  g_object_unref(lan_store);
+  g_object_unref(lan_store_depr);
   gtk_tree_view_columns_autosize(GTK_TREE_VIEW(view));
 
-  selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
-  lan_selection = selection;
-  gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
+  selection_depr = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
+  lan_selection_depr = selection_depr;
+  gtk_tree_selection_set_mode(selection_depr, GTK_SELECTION_SINGLE);
 
   controller = gtk_event_controller_focus_new();
   g_signal_connect(controller, "enter",
@@ -1611,8 +1750,11 @@ GtkWidget *create_network_page(void)
   gtk_widget_add_controller(view, controller);
 
   g_signal_connect(view, "row-activated",
-                   G_CALLBACK(network_activate_callback), NULL);
-  g_signal_connect(selection, "changed",
+                   G_CALLBACK(network_activate_callback_depr), NULL);
+  g_signal_connect(selection_depr, "changed",
+                   G_CALLBACK(network_list_callback_depr), NULL);
+
+  g_signal_connect(lan_selection, "selection-changed",
                    G_CALLBACK(network_list_callback), NULL);
 
   add_treeview_column(view, _("Server Name"), G_TYPE_STRING, 0);
@@ -1638,23 +1780,90 @@ GtkWidget *create_network_page(void)
 
 
   /* Metaserver pane. */
-  meta_store = gtk_list_store_new(7, G_TYPE_STRING, /* host */
-                                  G_TYPE_INT,       /* port */
-                                  G_TYPE_STRING,    /* version */
-                                  G_TYPE_STRING,    /* state */
-                                  G_TYPE_INT,       /* nplayers */
-                                  G_TYPE_STRING,    /* humans */
-                                  G_TYPE_STRING);   /* message */
-
-  view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(meta_store));
+  meta_store_depr = gtk_list_store_new(7, G_TYPE_STRING, /* host */
+                                       G_TYPE_INT,       /* port */
+                                       G_TYPE_STRING,    /* version */
+                                       G_TYPE_STRING,    /* state */
+                                       G_TYPE_INT,       /* nplayers */
+                                       G_TYPE_STRING,    /* humans */
+                                       G_TYPE_STRING);   /* message */
+
+  meta_store = g_list_store_new(FC_TYPE_HOST_ROW);
+  meta_selection = gtk_single_selection_new(G_LIST_MODEL(meta_store));
+  list = gtk_column_view_new(GTK_SELECTION_MODEL(meta_selection));
+
+  factory = gtk_signal_list_item_factory_new();
+  g_signal_connect(factory, "bind", G_CALLBACK(host_factory_bind),
+                   GINT_TO_POINTER(host_row_host));
+  g_signal_connect(factory, "setup", G_CALLBACK(host_factory_setup),
+                   nullptr);
+
+  column = gtk_column_view_column_new(_("Host"), factory);
+  gtk_column_view_append_column(GTK_COLUMN_VIEW(list), column);
+
+  factory = gtk_signal_list_item_factory_new();
+  g_signal_connect(factory, "bind", G_CALLBACK(host_factory_bind),
+                   GINT_TO_POINTER(host_row_port));
+  g_signal_connect(factory, "setup", G_CALLBACK(host_factory_setup),
+                   nullptr);
+
+  column = gtk_column_view_column_new(_("Port"), factory);
+  gtk_column_view_append_column(GTK_COLUMN_VIEW(list), column);
+
+  factory = gtk_signal_list_item_factory_new();
+  g_signal_connect(factory, "bind", G_CALLBACK(host_factory_bind),
+                   GINT_TO_POINTER(host_row_version));
+  g_signal_connect(factory, "setup", G_CALLBACK(host_factory_setup),
+                   nullptr);
+
+  column = gtk_column_view_column_new(_("Version"), factory);
+  gtk_column_view_append_column(GTK_COLUMN_VIEW(list), column);
+
+  factory = gtk_signal_list_item_factory_new();
+  g_signal_connect(factory, "bind", G_CALLBACK(host_factory_bind),
+                   GINT_TO_POINTER(host_row_state));
+  g_signal_connect(factory, "setup", G_CALLBACK(host_factory_setup),
+                   nullptr);
+
+  column = gtk_column_view_column_new(_("Status"), factory);
+  gtk_column_view_append_column(GTK_COLUMN_VIEW(list), column);
+
+  factory = gtk_signal_list_item_factory_new();
+  g_signal_connect(factory, "bind", G_CALLBACK(host_factory_bind),
+                   GINT_TO_POINTER(host_row_nplayers));
+  g_signal_connect(factory, "setup", G_CALLBACK(host_factory_setup),
+                   nullptr);
+
+  column = gtk_column_view_column_new(_("Players"), factory);
+  gtk_column_view_append_column(GTK_COLUMN_VIEW(list), column);
+
+  factory = gtk_signal_list_item_factory_new();
+  g_signal_connect(factory, "bind", G_CALLBACK(host_factory_bind),
+                   GINT_TO_POINTER(host_row_humans));
+  g_signal_connect(factory, "setup", G_CALLBACK(host_factory_setup),
+                   nullptr);
+
+  column = gtk_column_view_column_new(_("Humans"), factory);
+  gtk_column_view_append_column(GTK_COLUMN_VIEW(list), column);
+
+  factory = gtk_signal_list_item_factory_new();
+  g_signal_connect(factory, "bind", G_CALLBACK(host_factory_bind),
+                   GINT_TO_POINTER(host_row_message));
+  g_signal_connect(factory, "setup", G_CALLBACK(host_factory_setup),
+                   nullptr);
+
+  column = gtk_column_view_column_new(_("Comment"), factory);
+  gtk_column_view_append_column(GTK_COLUMN_VIEW(list), column);
+
+  view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(meta_store_depr));
   gtk_widget_set_hexpand(view, TRUE);
   gtk_widget_set_vexpand(view, TRUE);
-  g_object_unref(meta_store);
+  g_object_unref(meta_store_depr);
   gtk_tree_view_columns_autosize(GTK_TREE_VIEW(view));
 
-  selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
-  meta_selection = selection;
-  gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
+  selection_depr = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
+  meta_selection_depr = selection_depr;
+  gtk_tree_selection_set_mode(selection_depr, GTK_SELECTION_SINGLE);
 
   controller = gtk_event_controller_focus_new();
   g_signal_connect(controller, "enter",
@@ -1662,8 +1871,11 @@ GtkWidget *create_network_page(void)
   gtk_widget_add_controller(view, controller);
 
   g_signal_connect(view, "row-activated",
-                   G_CALLBACK(network_activate_callback), NULL);
-  g_signal_connect(selection, "changed",
+                   G_CALLBACK(network_activate_callback_depr), NULL);
+  g_signal_connect(selection_depr, "changed",
+                   G_CALLBACK(network_list_callback_depr), NULL);
+
+  g_signal_connect(meta_selection, "selection-changed",
                    G_CALLBACK(network_list_callback), NULL);
 
   add_treeview_column(view, _("Server Name"), G_TYPE_STRING, 0);
-- 
2.45.2

