1 /***********************************************************************
2  Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 ***********************************************************************/
13 
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 
21 #include <gtk/gtk.h>
22 
23 /* utility */
24 #include "log.h"
25 #include "mem.h"
26 #include "shared.h"
27 #include "support.h"
28 
29 /* common */
30 #include "diptreaty.h"
31 #include "fcintl.h"
32 #include "game.h"
33 #include "government.h"
34 #include "map.h"
35 #include "packets.h"
36 #include "player.h"
37 #include "research.h"
38 
39 /* client */
40 #include "chatline.h"
41 #include "client_main.h"
42 #include "climisc.h"
43 #include "options.h"
44 
45 /* client/gui-gtk-3.22 */
46 #include "diplodlg.h"
47 #include "gui_main.h"
48 #include "gui_stuff.h"
49 #include "mapview.h"
50 #include "plrdlg.h"
51 
52 #define MAX_NUM_CLAUSES 64
53 
54 struct Diplomacy_dialog {
55   struct Treaty treaty;
56   struct gui_dialog* dialog;
57 
58   GtkWidget *menu0;
59   GtkWidget *menu1;
60 
61   GtkWidget *image0;
62   GtkWidget *image1;
63 
64   GtkListStore *store;
65 };
66 
67 struct Diplomacy_notebook {
68   struct gui_dialog* dialog;
69   GtkWidget *notebook;
70 };
71 
72 #define SPECLIST_TAG dialog
73 #define SPECLIST_TYPE struct Diplomacy_dialog
74 #include "speclist.h"
75 
76 #define dialog_list_iterate(dialoglist, pdialog) \
77     TYPED_LIST_ITERATE(struct Diplomacy_dialog, dialoglist, pdialog)
78 #define dialog_list_iterate_end  LIST_ITERATE_END
79 
80 static struct dialog_list *dialog_list;
81 static struct Diplomacy_notebook *dipl_main;
82 
83 static struct Diplomacy_dialog *create_diplomacy_dialog(struct player *plr0,
84 						 struct player *plr1);
85 
86 static struct Diplomacy_dialog *find_diplomacy_dialog(int other_player_id);
87 static void popup_diplomacy_dialog(int other_player_id, int initiated_from);
88 static void diplomacy_dialog_map_callback(GtkWidget *w, gpointer data);
89 static void diplomacy_dialog_seamap_callback(GtkWidget *w, gpointer data);
90 static void diplomacy_dialog_tech_callback(GtkWidget *w, gpointer data);
91 static void diplomacy_dialog_city_callback(GtkWidget *w, gpointer data);
92 static void diplomacy_dialog_ceasefire_callback(GtkWidget *w, gpointer data);
93 static void diplomacy_dialog_peace_callback(GtkWidget *w, gpointer data);
94 static void diplomacy_dialog_alliance_callback(GtkWidget *w, gpointer data);
95 static void diplomacy_dialog_vision_callback(GtkWidget *w, gpointer data);
96 static void diplomacy_dialog_embassy_callback(GtkWidget *w, gpointer data);
97 static void close_diplomacy_dialog(struct Diplomacy_dialog *pdialog);
98 static void update_diplomacy_dialog(struct Diplomacy_dialog *pdialog);
99 static void diplo_dialog_returnkey(GtkWidget *w, gpointer data);
100 
101 static struct Diplomacy_notebook *diplomacy_main_create(void);
102 static void diplomacy_main_destroy(void);
103 static void diplomacy_main_response(struct gui_dialog *dlg, int response,
104                                     gpointer data);
105 
106 #define RESPONSE_CANCEL_MEETING 100
107 #define RESPONSE_CANCEL_MEETING_ALL 101
108 
109 /****************************************************************
110   Server tells us that either party has accepted treaty
111 *****************************************************************/
handle_diplomacy_accept_treaty(int counterpart,bool I_accepted,bool other_accepted)112 void handle_diplomacy_accept_treaty(int counterpart, bool I_accepted,
113 				    bool other_accepted)
114 {
115   struct Diplomacy_dialog *pdialog = find_diplomacy_dialog(counterpart);
116 
117   if (!pdialog) {
118     return;
119   }
120 
121   pdialog->treaty.accept0 = I_accepted;
122   pdialog->treaty.accept1 = other_accepted;
123 
124   update_diplomacy_dialog(pdialog);
125   gui_dialog_alert(pdialog->dialog);
126 }
127 
128 /****************************************************************
129   Someone is initiating meeting with us.
130 *****************************************************************/
handle_diplomacy_init_meeting(int counterpart,int initiated_from)131 void handle_diplomacy_init_meeting(int counterpart, int initiated_from)
132 {
133   popup_diplomacy_dialog(counterpart, initiated_from);
134 }
135 
136 
137 /****************************************************************
138   Meeting has been cancelled.
139 *****************************************************************/
handle_diplomacy_cancel_meeting(int counterpart,int initiated_from)140 void handle_diplomacy_cancel_meeting(int counterpart, int initiated_from)
141 {
142   struct Diplomacy_dialog *pdialog = find_diplomacy_dialog(counterpart);
143 
144   if (!pdialog) {
145     return;
146   }
147 
148   close_diplomacy_dialog(pdialog);
149 }
150 
151 /****************************************************************
152   Added clause to the meeting
153 *****************************************************************/
handle_diplomacy_create_clause(int counterpart,int giver,enum clause_type type,int value)154 void handle_diplomacy_create_clause(int counterpart, int giver,
155 				    enum clause_type type, int value)
156 {
157   struct Diplomacy_dialog *pdialog = find_diplomacy_dialog(counterpart);
158 
159   if (!pdialog) {
160     return;
161   }
162 
163   add_clause(&pdialog->treaty, player_by_number(giver), type, value);
164   update_diplomacy_dialog(pdialog);
165   gui_dialog_alert(pdialog->dialog);
166 }
167 
168 /****************************************************************
169   Removed clause from meeting.
170 *****************************************************************/
handle_diplomacy_remove_clause(int counterpart,int giver,enum clause_type type,int value)171 void handle_diplomacy_remove_clause(int counterpart, int giver,
172 				    enum clause_type type, int value)
173 {
174   struct Diplomacy_dialog *pdialog = find_diplomacy_dialog(counterpart);
175 
176   if (!pdialog) {
177     return;
178   }
179 
180   remove_clause(&pdialog->treaty, player_by_number(giver), type, value);
181   update_diplomacy_dialog(pdialog);
182   gui_dialog_alert(pdialog->dialog);
183 }
184 
185 /****************************************************************
186   Popup the dialog 10% inside the main-window
187 *****************************************************************/
popup_diplomacy_dialog(int other_player_id,int initiated_from)188 static void popup_diplomacy_dialog(int other_player_id, int initiated_from)
189 {
190   struct Diplomacy_dialog *pdialog = find_diplomacy_dialog(other_player_id);
191 
192   if (!can_client_issue_orders()) {
193     return;
194   }
195 
196   if (client.conn.playing->ai_controlled) {
197     return;			/* Don't show if we are AI controlled. */
198   }
199 
200   if (!pdialog) {
201     pdialog = create_diplomacy_dialog(client.conn.playing,
202 				      player_by_number(other_player_id));
203   }
204 
205   gui_dialog_present(pdialog->dialog);
206   /* We initated the meeting - Make the tab active */
207   if (player_by_number(initiated_from) == client.conn.playing) {
208     /* we have to raise the diplomacy meeting tab as well as the selected
209      * meeting. */
210     fc_assert_ret(dipl_main != NULL);
211     gui_dialog_raise(dipl_main->dialog);
212     gui_dialog_raise(pdialog->dialog);
213 
214     if (players_dialog_shell != NULL) {
215       gui_dialog_set_return_dialog(pdialog->dialog, players_dialog_shell);
216     }
217   }
218 }
219 
220 /****************************************************************************
221   Utility for g_list_sort(). See below.
222 ****************************************************************************/
sort_advance_names(gconstpointer a,gconstpointer b)223 static gint sort_advance_names(gconstpointer a, gconstpointer b)
224 {
225   const struct advance *padvance1 = (const struct advance *) a;
226   const struct advance *padvance2 = (const struct advance *) b;
227 
228   return fc_strcoll(advance_name_translation(padvance1),
229                     advance_name_translation(padvance2));
230 }
231 
232 /****************************************************************
233   Popup menu about adding clauses
234 *****************************************************************/
popup_add_menu(GtkMenuShell * parent,gpointer data)235 static void popup_add_menu(GtkMenuShell *parent, gpointer data)
236 {
237   struct Diplomacy_dialog *pdialog;
238   struct player *pgiver, *pother;
239   GtkWidget *item, *menu;
240 
241 
242   /* init. */
243   gtk_container_foreach(GTK_CONTAINER(parent),
244                         (GtkCallback) gtk_widget_destroy, NULL);
245 
246   pdialog = (struct Diplomacy_dialog *) data;
247   pgiver = (struct player *) g_object_get_data(G_OBJECT(parent), "plr");
248   pother = (pgiver == pdialog->treaty.plr0
249             ? pdialog->treaty.plr1 : pdialog->treaty.plr0);
250 
251 
252   /* Maps. */
253   menu = gtk_menu_new();
254   item = gtk_menu_item_new_with_mnemonic(_("World-map"));
255   gtk_menu_shell_append(GTK_MENU_SHELL(menu),item);
256   g_object_set_data(G_OBJECT(item), "plr", pgiver);
257   g_signal_connect(item, "activate",
258 		   G_CALLBACK(diplomacy_dialog_map_callback), pdialog);
259 
260   item = gtk_menu_item_new_with_mnemonic(_("Sea-map"));
261   gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
262   g_object_set_data(G_OBJECT(item), "plr", pgiver);
263   g_signal_connect(item, "activate",
264 		   G_CALLBACK(diplomacy_dialog_seamap_callback), pdialog);
265 
266   item = gtk_menu_item_new_with_mnemonic(_("_Maps"));
267   gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
268   gtk_menu_shell_append(GTK_MENU_SHELL(parent), item);
269   gtk_widget_show_all(item);
270 
271   /* Trading: advances */
272   if (game.info.trading_tech) {
273     const struct research *gresearch = research_get(pgiver);
274     const struct research *oresearch = research_get(pother);
275     GtkWidget *advance_item;
276     GList *sorting_list = NULL;
277 
278     advance_item = gtk_menu_item_new_with_mnemonic(_("_Advances"));
279     gtk_menu_shell_append(GTK_MENU_SHELL(parent), advance_item);
280 
281     advance_iterate(A_FIRST, padvance) {
282       Tech_type_id i = advance_number(padvance);
283 
284       if (research_invention_state(gresearch, i) == TECH_KNOWN
285           && research_invention_gettable(oresearch, i,
286                                          game.info.tech_trade_allow_holes)
287           && (research_invention_state(oresearch, i) == TECH_UNKNOWN
288               || research_invention_state(oresearch, i)
289                  == TECH_PREREQS_KNOWN)) {
290         sorting_list = g_list_prepend(sorting_list, padvance);
291       }
292     } advance_iterate_end;
293 
294     if (NULL == sorting_list) {
295       /* No advance. */
296       gtk_widget_set_sensitive(advance_item, FALSE);
297     } else {
298       GList *list_item;
299       const struct advance *padvance;
300 
301       sorting_list = g_list_sort(sorting_list, sort_advance_names);
302       menu = gtk_menu_new();
303 
304       /* TRANS: All technologies menu item in the diplomatic dialog. */
305       item = gtk_menu_item_new_with_label(_("All advances"));
306       gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
307       g_object_set_data(G_OBJECT(item), "player_from",
308                         GINT_TO_POINTER(player_number(pgiver)));
309       g_object_set_data(G_OBJECT(item), "player_to",
310                         GINT_TO_POINTER(player_number(pother)));
311       g_signal_connect(item, "activate",
312                        G_CALLBACK(diplomacy_dialog_tech_callback),
313                        GINT_TO_POINTER(A_LAST));
314       gtk_menu_shell_append(GTK_MENU_SHELL(menu),
315                             gtk_separator_menu_item_new());
316 
317       for (list_item = sorting_list; NULL != list_item;
318            list_item = g_list_next(list_item)) {
319         padvance = (const struct advance *) list_item->data;
320         item =
321             gtk_menu_item_new_with_label(advance_name_translation(padvance));
322         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
323         g_object_set_data(G_OBJECT(item), "player_from",
324                           GINT_TO_POINTER(player_number(pgiver)));
325         g_object_set_data(G_OBJECT(item), "player_to",
326                           GINT_TO_POINTER(player_number(pother)));
327         g_signal_connect(item, "activate",
328                          G_CALLBACK(diplomacy_dialog_tech_callback),
329                          GINT_TO_POINTER(advance_number(padvance)));
330       }
331 
332       gtk_menu_item_set_submenu(GTK_MENU_ITEM(advance_item), menu);
333       g_list_free(sorting_list);
334     }
335 
336     gtk_widget_show_all(advance_item);
337   }
338 
339 
340   /* Trading: cities. */
341 
342   /****************************************************************
343   Creates a sorted list of plr0's cities, excluding the capital and
344   any cities not visible to plr1.  This means that you can only trade
345   cities visible to requesting player.
346 
347 			      - Kris Bubendorfer
348   *****************************************************************/
349   if (game.info.trading_city) {
350     int i = 0, j = 0, n = city_list_size(pgiver->cities);
351     struct city **city_list_ptrs;
352 
353     if (n > 0) {
354       city_list_ptrs = fc_malloc(sizeof(struct city *) * n);
355     } else {
356       city_list_ptrs = NULL;
357     }
358 
359     city_list_iterate(pgiver->cities, pcity) {
360       if (!is_capital(pcity)) {
361 	city_list_ptrs[i] = pcity;
362 	i++;
363       }
364     } city_list_iterate_end;
365 
366     qsort(city_list_ptrs, i, sizeof(struct city *), city_name_compare);
367 
368     menu = gtk_menu_new();
369 
370     for (j = 0; j < i; j++) {
371       item = gtk_menu_item_new_with_label(city_name_get(city_list_ptrs[j]));
372 
373       gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
374       g_signal_connect(item, "activate",
375 		       G_CALLBACK(diplomacy_dialog_city_callback),
376 			 GINT_TO_POINTER((player_number(pgiver) << 24) |
377 					 (player_number(pother) << 16) |
378 					 city_list_ptrs[j]->id));
379     }
380     free(city_list_ptrs);
381 
382     item = gtk_menu_item_new_with_mnemonic(_("_Cities"));
383     gtk_widget_set_sensitive(item, (i > 0));
384     gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
385     gtk_menu_shell_append(GTK_MENU_SHELL(parent), item);
386     gtk_widget_show_all(item);
387   }
388 
389 
390   /* Give shared vision. */
391   item = gtk_menu_item_new_with_mnemonic(_("_Give shared vision"));
392   g_object_set_data(G_OBJECT(item), "plr", pgiver);
393   g_signal_connect(item, "activate",
394 		   G_CALLBACK(diplomacy_dialog_vision_callback), pdialog);
395 
396   if (gives_shared_vision(pgiver, pother)) {
397     gtk_widget_set_sensitive(item, FALSE);
398   }
399   gtk_menu_shell_append(GTK_MENU_SHELL(parent), item);
400   gtk_widget_show(item);
401 
402 
403   /* Give embassy. */
404   item = gtk_menu_item_new_with_mnemonic(_("Give _embassy"));
405   g_object_set_data(G_OBJECT(item), "plr", pgiver);
406   g_signal_connect(item, "activate",
407 		   G_CALLBACK(diplomacy_dialog_embassy_callback), pdialog);
408 
409   /* Don't take in account the embassy effects. */
410   if (player_has_real_embassy(pother, pgiver)) {
411     gtk_widget_set_sensitive(item, FALSE);
412   }
413   gtk_menu_shell_append(GTK_MENU_SHELL(parent), item);
414   gtk_widget_show(item);
415 
416 
417   /* Pacts. */
418   if (pgiver == pdialog->treaty.plr0) {
419     enum diplstate_type ds;
420 
421     ds = player_diplstate_get(pgiver, pother)->type;
422 
423     menu = gtk_menu_new();
424     item = gtk_menu_item_new_with_mnemonic(Q_("?diplomatic_state:Cease-fire"));
425     gtk_menu_shell_append(GTK_MENU_SHELL(menu),item);
426     g_signal_connect(item, "activate",
427 		     G_CALLBACK(diplomacy_dialog_ceasefire_callback), pdialog);
428     gtk_widget_set_sensitive(item, ds != DS_CEASEFIRE && ds != DS_TEAM);
429 
430     item = gtk_menu_item_new_with_mnemonic(Q_("?diplomatic_state:Peace"));
431     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
432     g_signal_connect(item, "activate",
433 		     G_CALLBACK(diplomacy_dialog_peace_callback), pdialog);
434     gtk_widget_set_sensitive(item, ds != DS_PEACE && ds != DS_TEAM);
435 
436     item = gtk_menu_item_new_with_mnemonic(Q_("?diplomatic_state:Alliance"));
437     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
438     g_signal_connect(item, "activate",
439 		     G_CALLBACK(diplomacy_dialog_alliance_callback), pdialog);
440     gtk_widget_set_sensitive(item, ds != DS_ALLIANCE && ds != DS_TEAM);
441 
442     item = gtk_menu_item_new_with_mnemonic(_("_Pacts"));
443     gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
444     gtk_menu_shell_append(GTK_MENU_SHELL(parent), item);
445     gtk_widget_show_all(item);
446   }
447 }
448 
449 /****************************************************************
450   Some clause activated
451 *****************************************************************/
row_callback(GtkTreeView * view,GtkTreePath * path,GtkTreeViewColumn * col,gpointer data)452 static void row_callback(GtkTreeView *view, GtkTreePath *path,
453 			 GtkTreeViewColumn *col, gpointer data)
454 {
455   struct Diplomacy_dialog *pdialog = (struct Diplomacy_dialog *)data;
456   gint i;
457   gint *index;
458 
459   index = gtk_tree_path_get_indices(path);
460 
461   i = 0;
462   clause_list_iterate(pdialog->treaty.clauses, pclause) {
463     if (i == index[0]) {
464       dsend_packet_diplomacy_remove_clause_req(&client.conn,
465 					       player_number(pdialog->treaty.plr1),
466 					       player_number(pclause->from),
467 					       pclause->type,
468 					       pclause->value);
469       return;
470     }
471     i++;
472   } clause_list_iterate_end;
473 }
474 
475 /*****************************************************************************
476   Create the main tab for diplomatic meetings.
477 *****************************************************************************/
diplomacy_main_create(void)478 static struct Diplomacy_notebook *diplomacy_main_create(void)
479 {
480   /* Collect all meetings in one main tab. */
481   if (!dipl_main) {
482     GtkWidget *dipl_box, *dipl_sw;
483 
484     dipl_main = fc_malloc(sizeof(*dipl_main));
485     gui_dialog_new(&(dipl_main->dialog), GTK_NOTEBOOK(top_notebook),
486                   dipl_main->dialog, TRUE);
487     dipl_main->notebook = gtk_notebook_new();
488     gtk_notebook_set_tab_pos(GTK_NOTEBOOK(dipl_main->notebook),
489                              GTK_POS_RIGHT);
490     gtk_notebook_set_scrollable(GTK_NOTEBOOK(dipl_main->notebook), TRUE);
491 
492     dipl_sw = gtk_scrolled_window_new(NULL, NULL);
493     g_object_set(dipl_sw, "margin", 2, NULL);
494     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dipl_sw),
495                                    GTK_POLICY_AUTOMATIC,
496                                    GTK_POLICY_AUTOMATIC);
497     gtk_container_add(GTK_CONTAINER(dipl_sw), dipl_main->notebook);
498 
499     /* Buttons */
500     gui_dialog_add_button(dipl_main->dialog, NULL,
501                           _("Cancel _all meetings"),
502                           RESPONSE_CANCEL_MEETING_ALL);
503 
504     /* Responces for _all_ meetings. */
505     gui_dialog_response_set_callback(dipl_main->dialog,
506                                      diplomacy_main_response);
507     gui_dialog_set_default_response(dipl_main->dialog,
508                                     RESPONSE_CANCEL_MEETING_ALL);
509 
510     dipl_box = dipl_main->dialog->vbox;
511     gtk_container_add(GTK_CONTAINER(dipl_box), dipl_sw);
512 
513     gui_dialog_show_all(dipl_main->dialog);
514     gui_dialog_present(dipl_main->dialog);
515   }
516 
517   return dipl_main;
518 }
519 
520 /*****************************************************************************
521   Destroy main diplomacy dialog.
522 *****************************************************************************/
diplomacy_main_destroy(void)523 static void diplomacy_main_destroy(void)
524 {
525   if (dipl_main->dialog) {
526     gui_dialog_destroy(dipl_main->dialog);
527   }
528   free(dipl_main);
529   dipl_main = NULL;
530 }
531 
532 /*****************************************************************************
533   User has responded to whole diplomacy dialog (main tab).
534 *****************************************************************************/
diplomacy_main_response(struct gui_dialog * dlg,int response,gpointer data)535 static void diplomacy_main_response(struct gui_dialog *dlg, int response,
536                                     gpointer data)
537 {
538   if (!dipl_main) {
539     return;
540   }
541 
542   switch (response) {
543   default:
544     log_error("unhandled response in %s: %d", __FUNCTION__, response);
545     fc__fallthrough; /* No break. */
546   case GTK_RESPONSE_DELETE_EVENT:   /* GTK: delete the widget. */
547   case RESPONSE_CANCEL_MEETING_ALL: /* Cancel all meetings. */
548     dialog_list_iterate(dialog_list, adialog) {
549       /* This will do a round trip to the server ans close the diolag in the
550        * client. Closing the last dialog will also close the main tab.*/
551       dsend_packet_diplomacy_cancel_meeting_req(&client.conn,
552                                                 player_number(
553                                                   adialog->treaty.plr1));
554     } dialog_list_iterate_end;
555     break;
556   }
557 }
558 
559 /****************************************************************
560   Destroy diplomacy dialog
561 *****************************************************************/
diplomacy_destroy(struct Diplomacy_dialog * pdialog)562 static void diplomacy_destroy(struct Diplomacy_dialog* pdialog)
563 {
564   if (NULL != pdialog->dialog) {
565     /* pdialog->dialog may be NULL if the tab have been destroyed
566      * by an other way. */
567     gui_dialog_destroy(pdialog->dialog);
568   }
569   dialog_list_remove(dialog_list, pdialog);
570   free(pdialog);
571 
572   if (dialog_list) {
573     /* Diplomatic meetings in one main tab. */
574     if (dialog_list_size(dialog_list) > 0) {
575       if (dipl_main && dipl_main->dialog) {
576         gchar *buf;
577 
578         buf = g_strdup_printf(_("Diplomacy [%d]"), dialog_list_size(dialog_list));
579         gui_dialog_set_title(dipl_main->dialog, buf);
580         g_free(buf);
581       }
582     } else if (dipl_main) {
583       /* No meeting left - destroy main tab. */
584       diplomacy_main_destroy();
585     }
586   }
587 }
588 
589 /*****************************************************************************
590   User has responded to whole diplomacy dialog (one meeting).
591 *****************************************************************************/
diplomacy_response(struct gui_dialog * dlg,int response,gpointer data)592 static void diplomacy_response(struct gui_dialog *dlg, int response,
593                                gpointer data)
594 {
595   struct Diplomacy_dialog *pdialog = NULL;
596 
597   fc_assert_ret(data);
598   pdialog = (struct Diplomacy_dialog *)data;
599 
600   switch (response) {
601   case GTK_RESPONSE_ACCEPT:         /* Accept treaty. */
602     dsend_packet_diplomacy_accept_treaty_req(&client.conn,
603                                              player_number(
604                                                pdialog->treaty.plr1));
605     break;
606 
607   default:
608     log_error("unhandled response in %s: %d", __FUNCTION__, response);
609     fc__fallthrough; /* No break. */
610   case GTK_RESPONSE_DELETE_EVENT:   /* GTK: delete the widget. */
611   case GTK_RESPONSE_CANCEL:         /* GTK: cancel button. */
612   case RESPONSE_CANCEL_MEETING:     /* Cancel meetings. */
613     dsend_packet_diplomacy_cancel_meeting_req(&client.conn,
614                                               player_number(
615                                                 pdialog->treaty.plr1));
616     break;
617   }
618 }
619 
620 /*****************************************************************************
621   Setups diplomacy dialog widgets.
622 *****************************************************************************/
create_diplomacy_dialog(struct player * plr0,struct player * plr1)623 static struct Diplomacy_dialog *create_diplomacy_dialog(struct player *plr0,
624                                                         struct player *plr1)
625 {
626   struct Diplomacy_notebook *dipl_dialog;
627   GtkWidget *vbox, *hbox, *table, *mainbox;
628   GtkWidget *label, *sw, *view, *image, *spin;
629   GtkWidget *menubar, *menuitem, *menu, *notebook;
630   struct sprite *flag_spr;
631   GdkPixbuf *pb;
632   GtkListStore *store;
633   GtkCellRenderer *rend;
634   int i;
635 
636   struct Diplomacy_dialog *pdialog;
637   char plr_buf[4 * MAX_LEN_NAME];
638   gchar *buf;
639 
640   pdialog = fc_malloc(sizeof(*pdialog));
641 
642   dialog_list_prepend(dialog_list, pdialog);
643   init_treaty(&pdialog->treaty, plr0, plr1);
644 
645   /* Get main diplomacy tab. */
646   dipl_dialog = diplomacy_main_create();
647 
648   buf = g_strdup_printf(_("Diplomacy [%d]"), dialog_list_size(dialog_list));
649   gui_dialog_set_title(dipl_dialog->dialog, buf);
650   g_free(buf);
651 
652   notebook = dipl_dialog->notebook;
653 
654   gui_dialog_new(&(pdialog->dialog), GTK_NOTEBOOK(notebook), pdialog, FALSE);
655 
656   /* Buttons */
657   gui_dialog_add_button(pdialog->dialog, NULL,
658                         _("Accept treaty"), GTK_RESPONSE_ACCEPT);
659   gui_dialog_add_button(pdialog->dialog, NULL,
660                         _("Cancel meeting"), RESPONSE_CANCEL_MEETING);
661 
662   /* Responces for one meeting. */
663   gui_dialog_response_set_callback(pdialog->dialog, diplomacy_response);
664   gui_dialog_set_default_response(pdialog->dialog, RESPONSE_CANCEL_MEETING);
665 
666   /* Label for the new meeting. */
667   buf = g_strdup_printf("%s", nation_plural_for_player(plr1));
668   gui_dialog_set_title(pdialog->dialog, buf);
669 
670   /* Sort meeting tabs alphabetically by the tab label. */
671   for (i = 0; i < gtk_notebook_get_n_pages(GTK_NOTEBOOK(notebook)); i++) {
672     GtkWidget *prev_page
673       = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), i);
674     struct gui_dialog *prev_dialog
675       = g_object_get_data(G_OBJECT(prev_page), "gui-dialog-data");
676     const char *prev_label
677       = gtk_label_get_text(GTK_LABEL(prev_dialog->v.tab.label));
678 
679     if (fc_strcasecmp(buf, prev_label) < 0) {
680       gtk_notebook_reorder_child(GTK_NOTEBOOK(notebook),
681                                  pdialog->dialog->vbox, i);
682       break;
683     }
684   }
685   g_free(buf);
686 
687   /* Content. */
688   mainbox = pdialog->dialog->vbox;
689 
690   /* us. */
691   vbox = gtk_grid_new();
692   gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox),
693                                  GTK_ORIENTATION_VERTICAL);
694   gtk_grid_set_row_spacing(GTK_GRID(vbox), 5);
695   gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
696   gtk_container_add(GTK_CONTAINER(mainbox), vbox);
697 
698   /* Our nation. */
699   label = gtk_label_new(NULL);
700   gtk_widget_set_halign(label, GTK_ALIGN_CENTER);
701   gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
702   buf = g_strdup_printf("<span size=\"large\"><u>%s</u></span>",
703                         nation_plural_for_player(plr0));
704   gtk_label_set_markup(GTK_LABEL(label), buf);
705   g_free(buf);
706   gtk_container_add(GTK_CONTAINER(vbox), label);
707 
708   hbox = gtk_grid_new();
709   gtk_grid_set_column_spacing(GTK_GRID(hbox), 5);
710   gtk_container_add(GTK_CONTAINER(vbox), hbox);
711 
712   /* Our flag */
713   flag_spr = get_nation_flag_sprite(tileset, nation_of_player(plr0));
714 
715   pb = sprite_get_pixbuf(flag_spr);
716   image = gtk_image_new_from_pixbuf(pb);
717   g_object_unref(pb);
718   gtk_container_add(GTK_CONTAINER(hbox), image);
719 
720   /* Our name. */
721   label = gtk_label_new(NULL);
722   gtk_widget_set_hexpand(label, TRUE);
723   gtk_widget_set_halign(label, GTK_ALIGN_CENTER);
724   gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
725   buf = g_strdup_printf("<span size=\"large\" weight=\"bold\">%s</span>",
726                         ruler_title_for_player(plr0, plr_buf, sizeof(plr_buf)));
727   gtk_label_set_markup(GTK_LABEL(label), buf);
728   g_free(buf);
729   gtk_container_add(GTK_CONTAINER(hbox), label);
730 
731   image = gtk_image_new();
732   pdialog->image0 = image;
733   gtk_container_add(GTK_CONTAINER(hbox), image);
734 
735   /* Menu for clauses: we. */
736   menubar = gtk_aux_menu_bar_new();
737 
738   menu = gtk_menu_new();
739   pdialog->menu0 = menu;
740 
741   menuitem = gtk_menu_item_new_with_label(_("Add Clause..."));
742   gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
743   gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menuitem);
744   g_object_set_data(G_OBJECT(menu), "plr", plr0);
745   g_signal_connect(menu, "show", G_CALLBACK(popup_add_menu), pdialog);
746 
747   /* Main table for clauses and (if activated) gold trading: we. */
748   table = gtk_grid_new();
749   gtk_widget_set_halign(table, GTK_ALIGN_CENTER);
750   gtk_widget_set_valign(table, GTK_ALIGN_CENTER);
751   gtk_grid_set_column_spacing(GTK_GRID(table), 16);
752   gtk_container_add(GTK_CONTAINER(vbox), table);
753 
754   if (game.info.trading_gold) {
755     spin = gtk_spin_button_new_with_range(0.0, plr0->economic.gold + 0.1,
756                                           1.0);
757     gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin), 0);
758     gtk_entry_set_width_chars(GTK_ENTRY(spin), 16);
759     gtk_grid_attach(GTK_GRID(table), spin, 1, 0, 1, 1);
760     g_object_set_data(G_OBJECT(spin), "plr", plr0);
761     g_signal_connect_after(spin, "value-changed",
762                            G_CALLBACK(diplo_dialog_returnkey), pdialog);
763 
764     label = g_object_new(GTK_TYPE_LABEL, "use-underline", TRUE,
765                          "mnemonic-widget", spin, "label", _("Gold:"),
766                          "xalign", 0.0, "yalign", 0.5, NULL);
767     gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1);
768 
769     gtk_grid_attach(GTK_GRID(table), menubar, 2, 0, 1, 1);
770   } else {
771     gtk_grid_attach(GTK_GRID(table), menubar, 0, 0, 1, 1);
772   }
773 
774   /* them. */
775   vbox = gtk_grid_new();
776   gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox),
777                                  GTK_ORIENTATION_VERTICAL);
778   gtk_grid_set_row_spacing(GTK_GRID(vbox), 5);
779   gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
780   gtk_container_add(GTK_CONTAINER(mainbox), vbox);
781 
782   /* Their nation. */
783   label = gtk_label_new(NULL);
784   gtk_widget_set_halign(label, GTK_ALIGN_CENTER);
785   gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
786   buf = g_strdup_printf("<span size=\"large\"><u>%s</u></span>",
787                         nation_plural_for_player(plr1));
788   gtk_label_set_markup(GTK_LABEL(label), buf);
789   g_free(buf);
790   gtk_container_add(GTK_CONTAINER(vbox), label);
791 
792   hbox = gtk_grid_new();
793   gtk_grid_set_column_spacing(GTK_GRID(hbox), 5);
794   gtk_container_add(GTK_CONTAINER(vbox), hbox);
795 
796   /* Their flag */
797   flag_spr = get_nation_flag_sprite(tileset, nation_of_player(plr1));
798 
799   pb = sprite_get_pixbuf(flag_spr);
800   image = gtk_image_new_from_pixbuf(pb);
801   g_object_unref(pb);
802   gtk_container_add(GTK_CONTAINER(hbox), image);
803 
804   /* Their name. */
805   label = gtk_label_new(NULL);
806   gtk_widget_set_hexpand(label, TRUE);
807   gtk_widget_set_halign(label, GTK_ALIGN_CENTER);
808   gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
809   buf = g_strdup_printf("<span size=\"large\" weight=\"bold\">%s</span>",
810                         ruler_title_for_player(plr1, plr_buf, sizeof(plr_buf)));
811   gtk_label_set_markup(GTK_LABEL(label), buf);
812   g_free(buf);
813   gtk_container_add(GTK_CONTAINER(hbox), label);
814 
815   image = gtk_image_new();
816   pdialog->image1 = image;
817   gtk_container_add(GTK_CONTAINER(hbox), image);
818 
819   /* Menu for clauses: they. */
820   menubar = gtk_aux_menu_bar_new();
821 
822   menu = gtk_menu_new();
823   pdialog->menu1 = menu;
824 
825   menuitem = gtk_menu_item_new_with_label(_("Add Clause..."));
826   gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
827   gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menuitem);
828   g_object_set_data(G_OBJECT(menu), "plr", plr1);
829   g_signal_connect(menu, "show", G_CALLBACK(popup_add_menu), pdialog);
830 
831   /* Main table for clauses and (if activated) gold trading: they. */
832   table = gtk_grid_new();
833   gtk_widget_set_halign(table, GTK_ALIGN_CENTER);
834   gtk_widget_set_valign(table, GTK_ALIGN_CENTER);
835   gtk_grid_set_column_spacing(GTK_GRID(table), 16);
836   gtk_container_add(GTK_CONTAINER(vbox), table);
837 
838   if (game.info.trading_gold) {
839     spin = gtk_spin_button_new_with_range(0.0, plr1->economic.gold + 0.1,
840                                           1.0);
841     gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin), 0);
842     gtk_entry_set_width_chars(GTK_ENTRY(spin), 16);
843     gtk_grid_attach(GTK_GRID(table), spin, 1, 0, 1, 1);
844     g_object_set_data(G_OBJECT(spin), "plr", plr1);
845     g_signal_connect_after(spin, "value-changed",
846                            G_CALLBACK(diplo_dialog_returnkey), pdialog);
847 
848     label = g_object_new(GTK_TYPE_LABEL, "use-underline", TRUE,
849                          "mnemonic-widget", spin, "label", _("Gold:"),
850                          "xalign", 0.0, "yalign", 0.5, NULL);
851     gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1);
852 
853     gtk_grid_attach(GTK_GRID(table), menubar, 2, 0, 1, 1);
854   } else {
855     gtk_grid_attach(GTK_GRID(table), menubar, 0, 0, 1, 1);
856   }
857 
858   /* Clauses. */
859   mainbox = gtk_grid_new();
860   gtk_orientable_set_orientation(GTK_ORIENTABLE(mainbox),
861                                  GTK_ORIENTATION_VERTICAL);
862   gtk_container_add(GTK_CONTAINER(pdialog->dialog->vbox), mainbox);
863 
864   store = gtk_list_store_new(1, G_TYPE_STRING);
865   pdialog->store = store;
866 
867   view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
868   gtk_widget_set_hexpand(view, TRUE);
869   gtk_widget_set_vexpand(view, TRUE);
870   gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
871   g_object_unref(store);
872   gtk_widget_set_size_request(view, 320, 100);
873 
874   rend = gtk_cell_renderer_text_new();
875   gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, NULL,
876     rend, "text", 0, NULL);
877 
878   sw = gtk_scrolled_window_new(NULL, NULL);
879   g_object_set(sw, "margin", 2, NULL);
880   gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
881                                       GTK_SHADOW_ETCHED_IN);
882   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
883                                  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
884   gtk_container_add(GTK_CONTAINER(sw), view);
885 
886   label = g_object_new(GTK_TYPE_LABEL,
887     "use-underline", TRUE,
888     "mnemonic-widget", view,
889     "label", _("C_lauses:"),
890     "xalign", 0.0,
891     "yalign", 0.5,
892     NULL);
893 
894   vbox = gtk_grid_new();
895   gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox),
896                                  GTK_ORIENTATION_VERTICAL);
897   gtk_container_add(GTK_CONTAINER(mainbox), vbox);
898   gtk_container_add(GTK_CONTAINER(vbox), label);
899   gtk_container_add(GTK_CONTAINER(vbox), sw);
900 
901   gtk_widget_show_all(mainbox);
902 
903   g_signal_connect(view, "row_activated", G_CALLBACK(row_callback), pdialog);
904 
905   update_diplomacy_dialog(pdialog);
906   gui_dialog_show_all(pdialog->dialog);
907 
908   return pdialog;
909 }
910 
911 /**************************************************************************
912   Update diplomacy dialog
913 **************************************************************************/
update_diplomacy_dialog(struct Diplomacy_dialog * pdialog)914 static void update_diplomacy_dialog(struct Diplomacy_dialog *pdialog)
915 {
916   GtkListStore *store;
917   GtkTreeIter it;
918   bool blank = TRUE;
919   GdkPixbuf *pixbuf;
920 
921   store = pdialog->store;
922 
923   gtk_list_store_clear(store);
924   clause_list_iterate(pdialog->treaty.clauses, pclause) {
925     char buf[128];
926 
927     client_diplomacy_clause_string(buf, sizeof(buf), pclause);
928 
929     gtk_list_store_append(store, &it);
930     gtk_list_store_set(store, &it, 0, buf, -1);
931     blank = FALSE;
932   } clause_list_iterate_end;
933 
934   if (blank) {
935     gtk_list_store_append(store, &it);
936     gtk_list_store_set(store, &it, 0,
937 		       _("--- This treaty is blank. "
938 		 	 "Please add some clauses. ---"), -1);
939   }
940 
941   pixbuf = get_thumb_pixbuf(pdialog->treaty.accept0);
942   gtk_image_set_from_pixbuf(GTK_IMAGE(pdialog->image0), pixbuf);
943   g_object_unref(G_OBJECT(pixbuf));
944   pixbuf = get_thumb_pixbuf(pdialog->treaty.accept1);
945   gtk_image_set_from_pixbuf(GTK_IMAGE(pdialog->image1), pixbuf);
946   g_object_unref(G_OBJECT(pixbuf));
947 }
948 
949 /****************************************************************************
950   Callback for the diplomatic dialog: give tech.
951 ****************************************************************************/
diplomacy_dialog_tech_callback(GtkWidget * w,gpointer data)952 static void diplomacy_dialog_tech_callback(GtkWidget *w, gpointer data)
953 {
954   int giver, dest, other, tech;
955 
956   giver = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "player_from"));
957   dest = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "player_to"));
958   tech = GPOINTER_TO_INT(data);
959   if (player_by_number(giver) == client_player()) {
960     other = dest;
961   } else {
962     other = giver;
963   }
964 
965   if (A_LAST == tech) {
966     /* All techs. */
967     struct player *pgiver = player_by_number(giver);
968     struct player *pdest = player_by_number(dest);
969     const struct research *dresearch, *gresearch;
970 
971     fc_assert_ret(NULL != pgiver);
972     fc_assert_ret(NULL != pdest);
973 
974     dresearch = research_get(pdest);
975     gresearch = research_get(pgiver);
976     advance_iterate(A_FIRST, padvance) {
977       Tech_type_id i = advance_number(padvance);
978 
979       if (research_invention_state(gresearch, i) == TECH_KNOWN
980           && research_invention_gettable(dresearch, i,
981                                          game.info.tech_trade_allow_holes)
982           && (research_invention_state(dresearch, i) == TECH_UNKNOWN
983               || research_invention_state(dresearch, i)
984                  == TECH_PREREQS_KNOWN)) {
985         dsend_packet_diplomacy_create_clause_req(&client.conn, other, giver,
986                                                  CLAUSE_ADVANCE, i);
987       }
988     } advance_iterate_end;
989   } else {
990     /* Only one tech. */
991     dsend_packet_diplomacy_create_clause_req(&client.conn, other, giver,
992                                              CLAUSE_ADVANCE, tech);
993   }
994 }
995 
996 /****************************************************************
997 Callback for trading cities
998 			      - Kris Bubendorfer
999 *****************************************************************/
diplomacy_dialog_city_callback(GtkWidget * w,gpointer data)1000 static void diplomacy_dialog_city_callback(GtkWidget * w, gpointer data)
1001 {
1002   size_t choice = GPOINTER_TO_UINT(data);
1003   int giver = (choice >> 24) & 0xff, dest = (choice >> 16) & 0xff, other;
1004   int city = choice & 0xffff;
1005 
1006   if (player_by_number(giver) == client.conn.playing) {
1007     other = dest;
1008   } else {
1009     other = giver;
1010   }
1011 
1012   dsend_packet_diplomacy_create_clause_req(&client.conn, other, giver,
1013 					   CLAUSE_CITY, city);
1014 }
1015 
1016 /****************************************************************
1017   Map menu item activated
1018 *****************************************************************/
diplomacy_dialog_map_callback(GtkWidget * w,gpointer data)1019 static void diplomacy_dialog_map_callback(GtkWidget *w, gpointer data)
1020 {
1021   struct Diplomacy_dialog *pdialog = (struct Diplomacy_dialog *)data;
1022   struct player *pgiver;
1023 
1024   pgiver = (struct player *)g_object_get_data(G_OBJECT(w), "plr");
1025 
1026   dsend_packet_diplomacy_create_clause_req(&client.conn,
1027 					   player_number(pdialog->treaty.plr1),
1028 					   player_number(pgiver), CLAUSE_MAP, 0);
1029 }
1030 
1031 /****************************************************************
1032  Seamap menu item activated
1033 *****************************************************************/
diplomacy_dialog_seamap_callback(GtkWidget * w,gpointer data)1034 static void diplomacy_dialog_seamap_callback(GtkWidget *w, gpointer data)
1035 {
1036   struct Diplomacy_dialog *pdialog = (struct Diplomacy_dialog *)data;
1037   struct player *pgiver;
1038 
1039   pgiver = (struct player *)g_object_get_data(G_OBJECT(w), "plr");
1040 
1041   dsend_packet_diplomacy_create_clause_req(&client.conn,
1042 					   player_number(pdialog->treaty.plr1),
1043 					   player_number(pgiver), CLAUSE_SEAMAP,
1044 					   0);
1045 }
1046 
1047 /****************************************************************
1048   Adding pact clause
1049 *****************************************************************/
diplomacy_dialog_add_pact_clause(GtkWidget * w,gpointer data,int type)1050 static void diplomacy_dialog_add_pact_clause(GtkWidget *w, gpointer data,
1051 					     int type)
1052 {
1053   struct Diplomacy_dialog *pdialog = (struct Diplomacy_dialog *)data;
1054 
1055   dsend_packet_diplomacy_create_clause_req(&client.conn,
1056 					   player_number(pdialog->treaty.plr1),
1057 					   player_number(pdialog->treaty.plr0),
1058 					   type, 0);
1059 }
1060 
1061 /****************************************************************
1062   Ceasefire pact menu item activated
1063 *****************************************************************/
diplomacy_dialog_ceasefire_callback(GtkWidget * w,gpointer data)1064 static void diplomacy_dialog_ceasefire_callback(GtkWidget *w, gpointer data)
1065 {
1066   diplomacy_dialog_add_pact_clause(w, data, CLAUSE_CEASEFIRE);
1067 }
1068 
1069 /****************************************************************
1070   Peace pact menu item activated
1071 *****************************************************************/
diplomacy_dialog_peace_callback(GtkWidget * w,gpointer data)1072 static void diplomacy_dialog_peace_callback(GtkWidget *w, gpointer data)
1073 {
1074   diplomacy_dialog_add_pact_clause(w, data, CLAUSE_PEACE);
1075 }
1076 
1077 /****************************************************************
1078   Alliance pact menu item activated
1079 *****************************************************************/
diplomacy_dialog_alliance_callback(GtkWidget * w,gpointer data)1080 static void diplomacy_dialog_alliance_callback(GtkWidget *w, gpointer data)
1081 {
1082   diplomacy_dialog_add_pact_clause(w, data, CLAUSE_ALLIANCE);
1083 }
1084 
1085 /****************************************************************
1086   Shared vision menu item activated
1087 *****************************************************************/
diplomacy_dialog_vision_callback(GtkWidget * w,gpointer data)1088 static void diplomacy_dialog_vision_callback(GtkWidget *w, gpointer data)
1089 {
1090   struct Diplomacy_dialog *pdialog = (struct Diplomacy_dialog *) data;
1091   struct player *pgiver =
1092       (struct player *) g_object_get_data(G_OBJECT(w), "plr");
1093 
1094   dsend_packet_diplomacy_create_clause_req(&client.conn,
1095 					   player_number(pdialog->treaty.plr1),
1096 					   player_number(pgiver), CLAUSE_VISION,
1097 					   0);
1098 }
1099 
1100 /****************************************************************
1101   Embassy menu item activated
1102 *****************************************************************/
diplomacy_dialog_embassy_callback(GtkWidget * w,gpointer data)1103 static void diplomacy_dialog_embassy_callback(GtkWidget *w, gpointer data)
1104 {
1105   struct Diplomacy_dialog *pdialog = (struct Diplomacy_dialog *) data;
1106   struct player *pgiver =
1107       (struct player *) g_object_get_data(G_OBJECT(w), "plr");
1108 
1109   dsend_packet_diplomacy_create_clause_req(&client.conn,
1110 					   player_number(pdialog->treaty.plr1),
1111 					   player_number(pgiver), CLAUSE_EMBASSY,
1112 					   0);
1113 }
1114 
1115 
1116 /*****************************************************************
1117   Close diplomacy dialog
1118 *****************************************************************/
close_diplomacy_dialog(struct Diplomacy_dialog * pdialog)1119 void close_diplomacy_dialog(struct Diplomacy_dialog *pdialog)
1120 {
1121   diplomacy_destroy(pdialog);
1122 }
1123 
1124 /*****************************************************************
1125   Initialize diplomacy dialog
1126 *****************************************************************/
diplomacy_dialog_init(void)1127 void diplomacy_dialog_init(void)
1128 {
1129   dialog_list = dialog_list_new();
1130   dipl_main = NULL;
1131 }
1132 
1133 /*****************************************************************
1134   Free resources allocated for diplomacy dialog
1135 *****************************************************************/
diplomacy_dialog_done(void)1136 void diplomacy_dialog_done(void)
1137 {
1138   dialog_list_destroy(dialog_list);
1139 }
1140 
1141 /*****************************************************************
1142   Find diplomacy dialog between player and other player
1143 *****************************************************************/
find_diplomacy_dialog(int other_player_id)1144 static struct Diplomacy_dialog *find_diplomacy_dialog(int other_player_id)
1145 {
1146   struct player *plr0 = client.conn.playing;
1147   struct player *plr1 = player_by_number(other_player_id);
1148 
1149   dialog_list_iterate(dialog_list, pdialog) {
1150     if ((pdialog->treaty.plr0 == plr0 && pdialog->treaty.plr1 == plr1) ||
1151 	(pdialog->treaty.plr0 == plr1 && pdialog->treaty.plr1 == plr0)) {
1152       return pdialog;
1153     }
1154   } dialog_list_iterate_end;
1155 
1156   return NULL;
1157 }
1158 
1159 /*****************************************************************
1160   User hit enter after entering gold amount
1161 *****************************************************************/
diplo_dialog_returnkey(GtkWidget * w,gpointer data)1162 static void diplo_dialog_returnkey(GtkWidget *w, gpointer data)
1163 {
1164   struct Diplomacy_dialog *pdialog = (struct Diplomacy_dialog *) data;
1165   struct player *pgiver =
1166       (struct player *) g_object_get_data(G_OBJECT(w), "plr");
1167   int amount = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w));
1168 
1169   if (amount >= 0 && amount <= pgiver->economic.gold) {
1170     dsend_packet_diplomacy_create_clause_req(&client.conn,
1171 					     player_number(pdialog->treaty.plr1),
1172 					     player_number(pgiver),
1173 					     CLAUSE_GOLD, amount);
1174   } else {
1175     output_window_append(ftc_client, _("Invalid amount of gold specified."));
1176   }
1177 }
1178 
1179 /*****************************************************************
1180   Close all dialogs, for when client disconnects from game.
1181 *****************************************************************/
close_all_diplomacy_dialogs(void)1182 void close_all_diplomacy_dialogs(void)
1183 {
1184   while (dialog_list_size(dialog_list) > 0) {
1185     close_diplomacy_dialog(dialog_list_get(dialog_list, 0));
1186   }
1187 }
1188