tRestore GtkTable for GTK2 builds - vaccinewars - be a doctor and try to vaccinate the world
git clone git://src.adamsgaard.dk/vaccinewars
Log
Files
Refs
README
LICENSE
---
commit 696618c1aea3a0e97fbb00051dfdaca143df93da
parent 716bcc4acfaee8c200ef0b2edf178f5ad3efd3ce
Author: Ben Webb 
Date:   Thu, 31 Dec 2020 17:58:22 -0800

Restore GtkTable for GTK2 builds

Provide an API similar to that of the 'real'
GtkGrid, which we can implement using GtkTable
when using GTK2. This should allow us to build
for GTK3 using GtkGrid, or GTK2 using GtkTable,
using the same codebase.

Diffstat:
  M src/gtkport/gtkport.c               |      41 +++++++++++++++++++++++++++++++
  M src/gtkport/gtkport.h               |      53 ++++++++++++++++++++++---------
  M src/gui_client/gtk_client.c         |     117 +++++++++++++------------------
  M src/gui_client/newgamedia.c         |      24 ++++++++++--------------
  M src/gui_client/optdialog.c          |      90 +++++++++++++-------------------

5 files changed, 172 insertions(+), 153 deletions(-)
---
diff --git a/src/gtkport/gtkport.c b/src/gtkport/gtkport.c
t@@ -5494,6 +5494,47 @@ gchar *GtkGetFile(const GtkWidget *parent, const gchar *oldname,
   return ret;
 }
 
+#if !CYGWIN && \
+  (GTK_MAJOR_VERSION > 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 4))
+/* GtkGrid does not take a size, unlike GtkTable */
+GtkWidget *dp_gtk_grid_new(guint rows, guint cols, gboolean homogeneous)
+{
+  GtkWidget *grid = gtk_grid_new();
+  if (homogeneous) {
+    gtk_grid_set_row_homogeneous(GTK_GRID(grid), TRUE);
+    gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE);
+  }
+  return grid;
+}
+
+void dp_gtk_grid_attach(GtkGrid *grid, GtkWidget *child,
+                        gint left, gint top,
+                        gint width, gint height, gboolean expand)
+{
+  gtk_grid_attach(grid, child, left, top, width, height);
+  if (expand) {
+    gtk_widget_set_hexpand(child, TRUE);
+  }
+}
+#else
+/* Implementation for older GTK or Win32, using GtkTable */
+GtkWidget *dp_gtk_grid_new(guint rows, guint columns, gboolean homogeneous)
+{
+  GtkWidget *table = gtk_table_new(rows, columns, homogeneous);
+  return table;
+}
+
+void dp_gtk_grid_attach(GtkGrid *grid, GtkWidget *child,
+                        gint left, gint top,
+                        gint width, gint height, gboolean expand)
+{
+  gtk_table_attach(grid, child, left, left + width, top, top + height,
+                   expand ? (GTK_EXPAND | GTK_FILL) : GTK_SHRINK,
+                   expand ? (GTK_EXPAND | GTK_FILL) : GTK_SHRINK, 0, 0);
+}
+#endif
+
+
 #endif /* CYGWIN */
 
 #if CYGWIN
diff --git a/src/gtkport/gtkport.h b/src/gtkport/gtkport.h
t@@ -381,8 +381,24 @@ void gtk_frame_set_shadow_type(GtkFrame *frame, GtkShadowType type);
 GtkWidget *gtk_text_new(GtkAdjustment *hadj, GtkAdjustment *vadj);
 GtkWidget *gtk_entry_new();
 void gtk_entry_set_visibility(GtkEntry *entry, gboolean visible);
-GtkWidget *gtk_table_new(guint rows, guint cols, gboolean homogeneous);
-void gtk_table_resize(GtkTable *table, guint rows, guint cols);
+
+/* GtkTable implementation */
+GtkWidget *dp_gtk_table_new(guint rows, guint cols, gboolean homogeneous);
+void dp_gtk_table_resize(GtkTable *table, guint rows, guint cols);
+void dp_gtk_table_attach(GtkTable *table, GtkWidget *widget,
+                         guint left_attach, guint right_attach,
+                         guint top_attach, guint bottom_attach,
+                         GtkAttachOptions xoptions, GtkAttachOptions yoptions,
+                         guint xpadding, guint ypadding);
+void dp_gtk_table_attach_defaults(GtkTable *table, GtkWidget *widget,
+                                  guint left_attach, guint right_attach,
+                                  guint top_attach, guint bottom_attach);
+void dp_gtk_table_set_row_spacing(GtkTable *table, guint row, guint spacing);
+void dp_gtk_table_set_col_spacing(GtkTable *table, guint column,
+                                  guint spacing);
+void dp_gtk_table_set_row_spacings(GtkTable *table, guint spacing);
+void dp_gtk_table_set_col_spacings(GtkTable *table, guint spacing);
+
 GSList *gtk_radio_button_get_group(GtkRadioButton *radio_button);
 void gtk_editable_insert_text(GtkEditable *editable, const gchar *new_text,
                               gint new_text_length, gint *position);
t@@ -401,19 +417,6 @@ void gtk_text_freeze(GtkText *text);
 void gtk_text_thaw(GtkText *text);
 GtkTextBuffer *gtk_text_view_get_buffer(GtkText *text);
 void gtk_text_buffer_create_tag(GtkTextBuffer *buffer, const gchar *name, ...);
-void gtk_table_attach(GtkTable *table, GtkWidget *widget,
-                      guint left_attach, guint right_attach,
-                      guint top_attach, guint bottom_attach,
-                      GtkAttachOptions xoptions, GtkAttachOptions yoptions,
-                      guint xpadding, guint ypadding);
-void gtk_table_attach_defaults(GtkTable *table, GtkWidget *widget,
-                               guint left_attach, guint right_attach,
-                               guint top_attach, guint bottom_attach);
-void gtk_table_set_row_spacing(GtkTable *table, guint row, guint spacing);
-void gtk_table_set_col_spacing(GtkTable *table, guint column,
-                               guint spacing);
-void gtk_table_set_row_spacings(GtkTable *table, guint spacing);
-void gtk_table_set_col_spacings(GtkTable *table, guint spacing);
 void gtk_box_pack_start(GtkBox *box, GtkWidget *child, gboolean Expand,
                         gboolean Fill, gint Padding);
 void gtk_toggle_button_toggled(GtkToggleButton *toggle_button);
t@@ -645,4 +648,24 @@ gchar *GtkGetFile(const GtkWidget *parent, const gchar *oldname,
 void DisplayHTML(GtkWidget *parent, const gchar *bin, const gchar *target);
 GtkWidget *gtk_scrolled_tree_view_new(GtkWidget **pack_widg);
 
+/* GtkTable is used in GTK2 (and early GTK3) but GtkGrid is used in later
+ * GTK3 and GTK4. Provide an interface similar to GtkGrid that internally
+ * uses either GtkTable or GtkGrid. Use a dp_ prefix to avoid clashes with
+ * the real GtkTable */
+#if CYGWIN || GTK_MAJOR_VERSION < 3 \
+    || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 4)
+#define GTK_GRID GTK_TABLE
+typedef GtkTable GtkGrid;
+#define gtk_grid_set_row_spacing(grid, spacing) gtk_table_set_row_spacings(grid, spacing)
+#define gtk_grid_set_column_spacing(grid, spacing) gtk_table_set_col_spacings(grid, spacing)
+#define dp_gtk_grid_resize(grid, rows, cols) gtk_table_resize(grid, rows, cols)
+#else
+#define dp_gtk_grid_resize(grid, rows, cols) {}
+#endif
+
+GtkWidget *dp_gtk_grid_new(guint rows, guint columns, gboolean homogeneous);
+void dp_gtk_grid_attach(GtkGrid *grid, GtkWidget *child,
+                        gint left, gint top,
+                        gint width, gint height, gboolean expand);
+
 #endif /* __GTKPORT_H__ */
diff --git a/src/gui_client/gtk_client.c b/src/gui_client/gtk_client.c
t@@ -635,7 +635,7 @@ void PrepareHighScoreDialog(void)
                                GTK_WINDOW(ClientData.window));
 
   HiScoreDialog.vbox = vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 7);
-  HiScoreDialog.grid = grid = gtk_grid_new();
+  HiScoreDialog.grid = grid = dp_gtk_grid_new(NUMHISCORE, 4, FALSE);
   gtk_grid_set_row_spacing(GTK_GRID(grid), 5);
   gtk_grid_set_column_spacing(GTK_GRID(grid), 30);
 
t@@ -685,8 +685,7 @@ void AddScoreToDialog(char *Data)
   }
   label = gtk_label_new(spl1[0]);
   gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
-  gtk_grid_attach(GTK_GRID(HiScoreDialog.grid), label, 0, index, 1, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(HiScoreDialog.grid), label, 0, index, 1, 1, TRUE);
   if (bold) {
     GdkColor color;
 
t@@ -713,8 +712,7 @@ void AddScoreToDialog(char *Data)
   }
   label = gtk_label_new(spl2[0]);
   gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5);
-  gtk_grid_attach(GTK_GRID(HiScoreDialog.grid), label, 1, index, 1, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(HiScoreDialog.grid), label, 1, index, 1, 1, TRUE);
   if (bold) {
     gtk_widget_set_style(label, style);
   }
t@@ -735,8 +733,8 @@ void AddScoreToDialog(char *Data)
   if (slen > 8 && spl2[1][slen - 1] == ')' && spl2[1][slen - 8] == '(') {
     label = gtk_label_new(&spl2[1][slen - 8]);
     gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5);
-    gtk_grid_attach(GTK_GRID(HiScoreDialog.grid), label, 3, index, 1, 1);
-    gtk_widget_set_hexpand(label, TRUE);
+    dp_gtk_grid_attach(GTK_GRID(HiScoreDialog.grid), label, 3, index, 1, 1,
+                       TRUE);
     if (bold) {
       gtk_widget_set_style(label, style);
     }
t@@ -748,8 +746,7 @@ void AddScoreToDialog(char *Data)
   g_strchomp(spl2[1]);
   label = gtk_label_new(spl2[1]);
   gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-  gtk_grid_attach(GTK_GRID(HiScoreDialog.grid), label, 2, index, 1, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(HiScoreDialog.grid), label, 2, index, 1, 1, TRUE);
   if (bold) {
     gtk_widget_set_style(label, style);
   }
t@@ -923,13 +920,12 @@ static void CreateFightDialog(void)
 
   vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 7);
 
-  grid = gtk_grid_new();
+  grid = dp_gtk_grid_new(2, 4, FALSE);
   gtk_grid_set_row_spacing(GTK_GRID(grid), 7);
   gtk_grid_set_column_spacing(GTK_GRID(grid), 10);
 
   hsep = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
-  gtk_grid_attach(GTK_GRID(grid), hsep, 0, 1, 3, 1);
-  gtk_widget_set_hexpand(hsep, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), hsep, 0, 1, 3, 1, TRUE);
   gtk_widget_show_all(grid);
   gtk_box_pack_start(GTK_BOX(vbox), grid, FALSE, FALSE, 0);
   g_object_set_data(G_OBJECT(dialog), "grid", grid);
t@@ -1025,6 +1021,7 @@ static void UpdateCombatant(gchar *DefendName, int DefendBitches,
       g_array_set_size(combatants, i + 1);
       compt = &g_array_index(combatants, struct combatant, i);
 
+      dp_gtk_grid_resize(GTK_GRID(grid), i + 2, 4);
       RowIndex = i + 1;
     }
   } else {
t@@ -1063,16 +1060,18 @@ static void UpdateCombatant(gchar *DefendName, int DefendBitches,
     /* Display of the current player's name during combat */
     compt->name = gtk_label_new(DefendName[0] ? DefendName : _("You"));
 
-    gtk_grid_attach(GTK_GRID(grid), compt->name, 0, RowIndex, 1, 1);
+    dp_gtk_grid_attach(GTK_GRID(grid), compt->name, 0, RowIndex, 1, 1, FALSE);
     compt->bitches = gtk_label_new(DefendBitches >= 0 ? BitchText : "");
-    gtk_grid_attach(GTK_GRID(grid), compt->bitches, 1, RowIndex, 1, 1);
+    dp_gtk_grid_attach(GTK_GRID(grid), compt->bitches, 1, RowIndex, 1, 1,
+                       FALSE);
     compt->healthprog = gtk_progress_bar_new();
     gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(compt->healthprog),
                                   ProgPercent);
-    gtk_grid_attach(GTK_GRID(grid), compt->healthprog, 2, RowIndex, 1, 1);
-    gtk_widget_set_hexpand(compt->healthprog, TRUE);
+    dp_gtk_grid_attach(GTK_GRID(grid), compt->healthprog, 2, RowIndex, 1, 1,
+                       TRUE);
     compt->healthlabel = gtk_label_new(HealthText);
-    gtk_grid_attach(GTK_GRID(grid), compt->healthlabel, 3, RowIndex, 1, 1);
+    dp_gtk_grid_attach(GTK_GRID(grid), compt->healthlabel, 3, RowIndex, 1, 1,
+                       FALSE);
     gtk_widget_show(compt->name);
     gtk_widget_show(compt->bitches);
     gtk_widget_show(compt->healthprog);
t@@ -1495,9 +1494,7 @@ void Jet(GtkWidget *parent)
     row++;
   }
 
-  grid = gtk_grid_new();
-  gtk_grid_set_row_homogeneous(GTK_GRID(grid), TRUE);
-  gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE);
+  grid = dp_gtk_grid_new(row, col, TRUE);
 
   for (i = 0; i < NumLocation; i++) {
     if (i < 9) {
t@@ -1534,7 +1531,7 @@ void Jet(GtkWidget *parent)
     g_object_set_data(G_OBJECT(button), "dialog", dialog);
     g_signal_connect(G_OBJECT(button), "clicked",
                      G_CALLBACK(JetCallback), GINT_TO_POINTER(i));
-    gtk_grid_attach(GTK_GRID(grid), button, col, row, 1, 1);
+    dp_gtk_grid_attach(GTK_GRID(grid), button, col, row, 1, 1, TRUE);
   }
   gtk_box_pack_start(GTK_BOX(vbox), grid, TRUE, TRUE, 0);
 
t@@ -2089,77 +2086,61 @@ GtkWidget *CreateStatusWidgets(struct StatusWidgets *Status)
 {
   GtkWidget *grid, *label;
 
-  grid = gtk_grid_new();
+  grid = dp_gtk_grid_new(3, 6, FALSE);
   gtk_grid_set_row_spacing(GTK_GRID(grid), 3);
   gtk_grid_set_column_spacing(GTK_GRID(grid), 3);
   gtk_container_set_border_width(GTK_CONTAINER(grid), 3);
 
   label = Status->Location = gtk_label_new(NULL);
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 2, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 2, 1, TRUE);
 
   label = Status->Date = gtk_label_new(NULL);
-  gtk_grid_attach(GTK_GRID(grid), label, 2, 0, 2, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 2, 0, 2, 1, TRUE);
 
   /* Available space label in GTK+ client status display */
   label = Status->SpaceName = gtk_label_new(_("Space"));
 
-  gtk_grid_attach(GTK_GRID(grid), label, 4, 0, 1, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 4, 0, 1, 1, TRUE);
   label = Status->SpaceValue = gtk_label_new(NULL);
-  gtk_grid_attach(GTK_GRID(grid), label, 5, 0, 1, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 5, 0, 1, 1, TRUE);
 
   /* Player's cash label in GTK+ client status display */
   label = Status->CashName = gtk_label_new(_("Cash"));
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1, TRUE);
 
   label = Status->CashValue = gtk_label_new(NULL);
-  gtk_grid_attach(GTK_GRID(grid), label, 1, 1, 1, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 1, 1, 1, 1, TRUE);
 
   /* Player's debt label in GTK+ client status display */
   label = Status->DebtName = gtk_label_new(_("Debt"));
-  gtk_grid_attach(GTK_GRID(grid), label, 2, 1, 1, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 2, 1, 1, 1, TRUE);
 
   label = Status->DebtValue = gtk_label_new(NULL);
-  gtk_grid_attach(GTK_GRID(grid), label, 3, 1, 1, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 3, 1, 1, 1, TRUE);
 
   /* Player's bank balance label in GTK+ client status display */
   label = Status->BankName = gtk_label_new(_("Bank"));
-  gtk_grid_attach(GTK_GRID(grid), label, 4, 1, 1, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 4, 1, 1, 1, TRUE);
 
   label = Status->BankValue = gtk_label_new(NULL);
-  gtk_grid_attach(GTK_GRID(grid), label, 5, 1, 1, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 5, 1, 1, 1, TRUE);
 
   label = Status->GunsName = gtk_label_new(NULL);
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 2, 1, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 2, 1, 1, TRUE);
   label = Status->GunsValue = gtk_label_new(NULL);
-  gtk_grid_attach(GTK_GRID(grid), label, 1, 2, 1, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 1, 2, 1, 1, TRUE);
 
   label = Status->BitchesName = gtk_label_new(NULL);
-  gtk_grid_attach(GTK_GRID(grid), label, 2, 2, 1, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 2, 2, 1, 1, TRUE);
   label = Status->BitchesValue = gtk_label_new(NULL);
-  gtk_grid_attach(GTK_GRID(grid), label, 3, 2, 1, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 3, 2, 1, 1, TRUE);
 
   /* Player's health label in GTK+ client status display */
   label = Status->HealthName = gtk_label_new(_("Health"));
-  gtk_grid_attach(GTK_GRID(grid), label, 4, 2, 1, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 4, 2, 1, 1, TRUE);
 
   label = Status->HealthValue = gtk_label_new(NULL);
-  gtk_grid_attach(GTK_GRID(grid), label, 5, 2, 1, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 5, 2, 1, 1, TRUE);
   return grid;
 }
 
t@@ -2456,7 +2437,7 @@ void display_intro(GtkWidget *widget, gpointer data)
   gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
   g_free(VersionStr);
 
-  grid = gtk_grid_new();
+  grid = dp_gtk_grid_new(rows, cols, FALSE);
   gtk_grid_set_row_spacing(GTK_GRID(grid), 3);
   gtk_grid_set_column_spacing(GTK_GRID(grid), 3);
   for (i = 0; i < rows; i++) {
t@@ -2468,8 +2449,7 @@ void display_intro(GtkWidget *widget, gpointer data)
           } else {
             label = gtk_label_new(table_data[i][j]);
           }
-          gtk_grid_attach(GTK_GRID(grid), label, j, i, 1, 1);
-          gtk_widget_set_hexpand(label, TRUE);
+          dp_gtk_grid_attach(GTK_GRID(grid), label, j, i, 1, 1, TRUE);
         }
       }
     }
t@@ -2607,15 +2587,14 @@ void TransferDialog(gboolean Debt)
                                GTK_WINDOW(ClientData.window));
 
   vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 7);
-  grid = gtk_grid_new();
+  grid = dp_gtk_grid_new(4, 3, FALSE);
   gtk_grid_set_row_spacing(GTK_GRID(grid), 4);
   gtk_grid_set_column_spacing(GTK_GRID(grid), 4);
 
   /* Display of player's cash in bank or loan shark dialog */
   dpg_string_printf(text, _("Cash: %P"), ClientData.Play->Cash);
   label = gtk_label_new(text->str);
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 3, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 3, 1, TRUE);
 
   if (Debt) {
     /* Display of player's debt in loan shark dialog */
t@@ -2625,24 +2604,23 @@ void TransferDialog(gboolean Debt)
     dpg_string_printf(text, _("Bank: %P"), ClientData.Play->Bank);
   }
   label = gtk_label_new(text->str);
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 3, 1);
-  gtk_widget_set_hexpand(label, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 3, 1, TRUE);
 
   g_object_set_data(G_OBJECT(dialog), "debt", GINT_TO_POINTER(Debt));
   if (Debt) {
     /* Prompt for paying back a loan */
     label = gtk_label_new(_("Pay back:"));
-    gtk_grid_attach(GTK_GRID(grid), label, 0, 2, 1, 2);
+    dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 2, 1, 2, FALSE);
   } else {
     /* Radio button selected if you want to pay money into the bank */
     radio = gtk_radio_button_new_with_label(NULL, _("Deposit"));
     g_object_set_data(G_OBJECT(dialog), "deposit", radio);
     group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio));
-    gtk_grid_attach(GTK_GRID(grid), radio, 0, 2, 1, 1);
+    dp_gtk_grid_attach(GTK_GRID(grid), radio, 0, 2, 1, 1, FALSE);
 
     /* Radio button selected if you want to withdraw money from the bank */
     radio = gtk_radio_button_new_with_label(group, _("Withdraw"));
-    gtk_grid_attach(GTK_GRID(grid), radio, 0, 3, 1, 1);
+    dp_gtk_grid_attach(GTK_GRID(grid), radio, 0, 3, 1, 1, FALSE);
   }
   label = gtk_label_new(Currency.Symbol);
   entry = gtk_entry_new();
t@@ -2650,14 +2628,13 @@ void TransferDialog(gboolean Debt)
   g_object_set_data(G_OBJECT(dialog), "entry", entry);
   g_signal_connect(G_OBJECT(entry), "activate",
                    G_CALLBACK(TransferOK), dialog);
-  gtk_widget_set_hexpand(entry, TRUE);
 
   if (Currency.Prefix) {
-    gtk_grid_attach(GTK_GRID(grid), label, 1, 2, 1, 2);
-    gtk_grid_attach(GTK_GRID(grid), entry, 2, 2, 1, 2);
+    dp_gtk_grid_attach(GTK_GRID(grid), label, 1, 2, 1, 2, FALSE);
+    dp_gtk_grid_attach(GTK_GRID(grid), entry, 2, 2, 1, 2, TRUE);
   } else {
-    gtk_grid_attach(GTK_GRID(grid), label, 2, 2, 1, 2);
-    gtk_grid_attach(GTK_GRID(grid), entry, 1, 2, 1, 2);
+    dp_gtk_grid_attach(GTK_GRID(grid), label, 2, 2, 1, 2, FALSE);
+    dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 2, 1, 2, TRUE);
   }
 
   gtk_box_pack_start(GTK_BOX(vbox), grid, TRUE, TRUE, 0);
diff --git a/src/gui_client/newgamedia.c b/src/gui_client/newgamedia.c
t@@ -550,14 +550,14 @@ void NewGameDialog(Player *play)
 #ifdef NETWORKING
   vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 7);
   gtk_container_set_border_width(GTK_CONTAINER(vbox2), 8);
-  grid = gtk_grid_new();
+  grid = dp_gtk_grid_new(2, 2, FALSE);
   gtk_grid_set_row_spacing(GTK_GRID(grid), 4);
   gtk_grid_set_column_spacing(GTK_GRID(grid), 4);
 
   /* Prompt for hostname to connect to in GTK+ new game dialog */
   label = gtk_label_new(_("Host name"));
 
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1, FALSE);
   entry = stgam.hostname = gtk_entry_new();
 
   ServerEntry = "localhost";
t@@ -572,16 +572,14 @@ void NewGameDialog(Player *play)
     ServerEntry = ServerName;
 
   gtk_entry_set_text(GTK_ENTRY(entry), ServerEntry);
-  gtk_grid_attach(GTK_GRID(grid), entry, 1, 0, 1, 1);
-  gtk_widget_set_hexpand(entry, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 0, 1, 1, TRUE);
   label = gtk_label_new(_("Port"));
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1, FALSE);
   entry = stgam.port = gtk_entry_new();
   text = g_strdup_printf("%d", Port);
   gtk_entry_set_text(GTK_ENTRY(entry), text);
   g_free(text);
-  gtk_grid_attach(GTK_GRID(grid), entry, 1, 1, 1, 1);
-  gtk_widget_set_hexpand(entry, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 1, 1, 1, TRUE);
 
   gtk_box_pack_start(GTK_BOX(vbox2), grid, FALSE, FALSE, 0);
 
t@@ -742,20 +740,19 @@ static void SocksAuthDialog(NetworkBuffer *netbuf, gpointer data)
 
   vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 7);
 
-  grid = gtk_grid_new();
+  grid = dp_gtk_grid_new(2, 2, FALSE);
   gtk_grid_set_row_spacing(GTK_GRID(grid), 10);
   gtk_grid_set_column_spacing(GTK_GRID(grid), 5);
 
   label = gtk_label_new("User name:");
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1, FALSE);
 
   entry = gtk_entry_new();
   g_object_set_data(G_OBJECT(window), "username", (gpointer)entry);
-  gtk_grid_attach(GTK_GRID(grid), entry, 1, 0, 1, 1);
-  gtk_widget_set_hexpand(entry, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 0, 1, 1, TRUE);
 
   label = gtk_label_new("Password:");
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1, FALSE);
 
   entry = gtk_entry_new();
   g_object_set_data(G_OBJECT(window), "password", (gpointer)entry);
t@@ -765,8 +762,7 @@ static void SocksAuthDialog(NetworkBuffer *netbuf, gpointer data)
   gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
 #endif
 
-  gtk_grid_attach(GTK_GRID(grid), entry, 1, 1, 1, 1);
-  gtk_widget_set_hexpand(entry, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 1, 1, 1, TRUE);
 
   gtk_box_pack_start(GTK_BOX(vbox), grid, TRUE, TRUE, 0);
 
diff --git a/src/gui_client/optdialog.c b/src/gui_client/optdialog.c
t@@ -284,14 +284,13 @@ static void AddStructConfig(GtkWidget *grid, int row, gchar *structname,
     GtkWidget *check;
 
     check = gtk_check_button_new_with_label(_(member->label));
-    gtk_grid_attach(GTK_GRID(grid), check, 0, row, 2, 1);
-    gtk_widget_set_hexpand(check, TRUE);
+    dp_gtk_grid_attach(GTK_GRID(grid), check, 0, row, 2, 1, TRUE);
     AddConfigWidget(check, ind);
   } else {
     GtkWidget *label, *entry;
 
     label = gtk_label_new(_(member->label));
-    gtk_grid_attach(GTK_GRID(grid), label, 0, row, 1, 1);
+    dp_gtk_grid_attach(GTK_GRID(grid), label, 0, row, 1, 1, FALSE);
     if (gvar->IntVal && gvar->MaxVal > gvar->MinVal) {
       GtkAdjustment *spin_adj = (GtkAdjustment *)
           gtk_adjustment_new(gvar->MinVal, gvar->MinVal, gvar->MaxVal,
t@@ -300,8 +299,7 @@ static void AddStructConfig(GtkWidget *grid, int row, gchar *structname,
     } else {
       entry = gtk_entry_new();
     }
-    gtk_grid_attach(GTK_GRID(grid), entry, 1, row, 1, 1);
-    gtk_widget_set_hexpand(entry, TRUE);
+    dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, row, 1, 1, TRUE);
     AddConfigWidget(entry, ind);
   }
 }
t@@ -762,7 +760,7 @@ static GtkWidget *CreateList(gchar *structname, struct ConfigMembers *members)
   gtk_box_pack_start(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
   gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
 
-  grid = gtk_grid_new();
+  grid = dp_gtk_grid_new(nummembers + 1, 2, FALSE);
   gtk_grid_set_row_spacing(GTK_GRID(grid), 5);
   gtk_grid_set_column_spacing(GTK_GRID(grid), 5);
 
t@@ -857,64 +855,55 @@ void OptDialog(GtkWidget *widget, gpointer data)
 
   notebook = gtk_notebook_new();
 
-  grid = gtk_grid_new();
+  grid = dp_gtk_grid_new(8, 3, FALSE);
   gtk_grid_set_row_spacing(GTK_GRID(grid), 5);
   gtk_grid_set_column_spacing(GTK_GRID(grid), 5);
 
   check = NewConfigCheck("Sanitized", _("Remove drug references"));
-  gtk_grid_attach(GTK_GRID(grid), check, 0, 0, 1, 1);
+  dp_gtk_grid_attach(GTK_GRID(grid), check, 0, 0, 1, 1, FALSE);
 
   check = gtk_check_button_new_with_label(_("Unicode config file"));
   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), IsConfigFileUTF8());
-  gtk_grid_attach(GTK_GRID(grid), check, 1, 0, 2, 1);
-  gtk_widget_set_hexpand(check, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), check, 1, 0, 2, 1, TRUE);
   g_object_set_data(G_OBJECT(dialog), "unicode_check", check);
 
   label = gtk_label_new(_("Game length (turns)"));
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1, FALSE);
   entry = NewConfigEntry("NumTurns");
-  gtk_grid_attach(GTK_GRID(grid), entry, 1, 1, 2, 1);
-  gtk_widget_set_hexpand(entry, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 1, 2, 1, TRUE);
 
   label = gtk_label_new(_("Starting cash"));
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 2, 1, 1);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 2, 1, 1, FALSE);
   entry = NewConfigEntry("StartCash");
-  gtk_grid_attach(GTK_GRID(grid), entry, 1, 2, 2, 1);
-  gtk_widget_set_hexpand(entry, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 2, 2, 1, TRUE);
 
   label = gtk_label_new(_("Starting debt"));
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 3, 1, 1);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 3, 1, 1, FALSE);
   entry = NewConfigEntry("StartDebt");
-  gtk_grid_attach(GTK_GRID(grid), entry, 1, 3, 2, 1);
-  gtk_widget_set_hexpand(entry, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 3, 2, 1, TRUE);
 
   label = gtk_label_new(_("Currency symbol"));
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 4, 1, 1);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 4, 1, 1, FALSE);
   entry = NewConfigEntry("Currency.Symbol");
-  gtk_grid_attach(GTK_GRID(grid), entry, 1, 4, 1, 1);
-  gtk_widget_set_hexpand(entry, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 4, 1, 1, TRUE);
   check = NewConfigCheck("Currency.Prefix", _("Symbol prefixes prices"));
-  gtk_grid_attach(GTK_GRID(grid), check, 2, 4, 1, 1);
-  gtk_widget_set_hexpand(check, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), check, 2, 4, 1, 1, TRUE);
 
   label = gtk_label_new(_("Name of one bitch"));
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 5, 1, 1);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 5, 1, 1, FALSE);
   entry = NewConfigEntry("Names.Bitch");
-  gtk_grid_attach(GTK_GRID(grid), entry, 1, 5, 2, 1);
-  gtk_widget_set_hexpand(entry, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 5, 2, 1, TRUE);
 
   label = gtk_label_new(_("Name of several bitches"));
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 6, 1, 1);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 6, 1, 1, FALSE);
   entry = NewConfigEntry("Names.Bitches");
-  gtk_grid_attach(GTK_GRID(grid), entry, 1, 6, 2, 1);
-  gtk_widget_set_hexpand(entry, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 6, 2, 1, TRUE);
 
 #ifndef CYGWIN
   label = gtk_label_new(_("Web browser"));
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 7, 1, 1);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 7, 1, 1, FALSE);
   entry = NewConfigEntry("WebBrowser");
-  gtk_grid_attach(GTK_GRID(grid), entry, 1, 7, 2, 1);
-  gtk_widget_set_hexpand(entry, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 7, 2, 1, TRUE);
 #endif
 
   gtk_container_set_border_width(GTK_CONTAINER(grid), 7);
t@@ -936,20 +925,18 @@ void OptDialog(GtkWidget *widget, gpointer data)
   hsep = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
   gtk_box_pack_start(GTK_BOX(vbox2), hsep, FALSE, FALSE, 0);
 
-  grid = gtk_grid_new();
+  grid = dp_gtk_grid_new(2, 2, FALSE);
   gtk_grid_set_row_spacing(GTK_GRID(grid), 5);
   gtk_grid_set_column_spacing(GTK_GRID(grid), 5);
   label = gtk_label_new(_("Expensive string 1"));
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1, FALSE);
   entry = NewConfigEntry("Drugs.ExpensiveStr1");
-  gtk_grid_attach(GTK_GRID(grid), entry, 1, 0, 1, 1);
-  gtk_widget_set_hexpand(entry, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 0, 1, 1, TRUE);
 
   label = gtk_label_new(_("Expensive string 2"));
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1, FALSE);
   entry = NewConfigEntry("Drugs.ExpensiveStr2");
-  gtk_grid_attach(GTK_GRID(grid), entry, 1, 1, 1, 1);
-  gtk_widget_set_hexpand(entry, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 1, 1, 1, TRUE);
   gtk_box_pack_start(GTK_BOX(vbox2), grid, FALSE, FALSE, 0);
 
   label = gtk_label_new(_("Drugs"));
t@@ -966,38 +953,33 @@ void OptDialog(GtkWidget *widget, gpointer data)
   gtk_notebook_append_page(GTK_NOTEBOOK(notebook), hbox, label);
 
 #ifdef NETWORKING
-  grid = gtk_grid_new();
+  grid = dp_gtk_grid_new(6, 4, FALSE);
   gtk_grid_set_row_spacing(GTK_GRID(grid), 5);
   gtk_grid_set_column_spacing(GTK_GRID(grid), 5);
 
   check = NewConfigCheck("MetaServer.Active",
                          _("Server reports to metaserver"));
-  gtk_grid_attach(GTK_GRID(grid), check, 0, 0, 2, 1);
-  gtk_widget_set_hexpand(check, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), check, 0, 0, 2, 1, TRUE);
 
 #ifdef CYGWIN
   check = NewConfigCheck("MinToSysTray", _("Minimize to System Tray"));
-  gtk_grid_attach(GTK_GRID(grid), check, 2, 0, 2, 1);
-  gtk_widget_set_hexpand(check, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), check, 2, 0, 2, 1, TRUE);
 #endif
 
   label = gtk_label_new(_("Metaserver URL"));
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1, FALSE);
   entry = NewConfigEntry("MetaServer.URL");
-  gtk_grid_attach(GTK_GRID(grid), entry, 1, 1, 3, 1);
-  gtk_widget_set_hexpand(entry, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 1, 3, 1, TRUE);
 
   label = gtk_label_new(_("Comment"));
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 4, 1, 1);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 4, 1, 1, FALSE);
   entry = NewConfigEntry("MetaServer.Comment");
-  gtk_grid_attach(GTK_GRID(grid), entry, 1, 4, 3, 1);
-  gtk_widget_set_hexpand(entry, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 4, 3, 1, TRUE);
 
   label = gtk_label_new(_("MOTD (welcome message)"));
-  gtk_grid_attach(GTK_GRID(grid), label, 0, 5, 1, 1);
+  dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 5, 1, 1, FALSE);
   entry = NewConfigEntry("ServerMOTD");
-  gtk_grid_attach(GTK_GRID(grid), entry, 1, 5, 3, 1);
-  gtk_widget_set_hexpand(entry, TRUE);
+  dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 5, 3, 1, TRUE);
 
   gtk_container_set_border_width(GTK_CONTAINER(grid), 7);
   label = gtk_label_new(_("Server"));