tnewgamedia.c - vaccinewars - be a doctor and try to vaccinate the world
HTML git clone git://src.adamsgaard.dk/vaccinewars
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
tnewgamedia.c (25068B)
---
1 /************************************************************************
2 * newgamedia.c New game dialog *
3 * Copyright (C) 1998-2021 Ben Webb *
4 * Email: benwebb@users.sf.net *
5 * WWW: https://dopewars.sourceforge.io/ *
6 * *
7 * This program is free software; you can redistribute it and/or *
8 * modify it under the terms of the GNU General Public License *
9 * as published by the Free Software Foundation; either version 2 *
10 * of the License, or (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, *
20 * MA 02111-1307, USA. *
21 ************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <string.h>
28 #include <stdlib.h> /* For atoi */
29 #include <glib.h>
30
31 #include "dopewars.h"
32 #include "network.h"
33 #include "message.h"
34 #include "nls.h"
35 #include "gtkport/gtkport.h"
36 #include "gtk_client.h"
37 #include "newgamedia.h"
38
39 struct StartGameStruct {
40 GtkWidget *dialog, *name, *hostname, *port, *antique, *status,
41 *metaserv, *notebook;
42 Player *play;
43 #ifdef NETWORKING
44 CurlConnection *MetaConn;
45 GSList *NewMetaList;
46 NBCallBack sockstat;
47 #endif
48 };
49
50 static struct StartGameStruct stgam;
51
52 #ifdef NETWORKING
53 static void SocksAuthDialog(NetworkBuffer *netbuf, gpointer data);
54 static void FillMetaServerList(gboolean UseNewList);
55
56 /* List of servers on the metaserver */
57 static GSList *MetaList = NULL;
58
59 #endif /* NETWORKING */
60
61 /* Which notebook page to display in the New Game dialog */
62 static gint NewGameType = 0;
63
64 static gboolean GetStartGamePlayerName(gchar **PlayerName)
65 {
66 g_free(*PlayerName);
67 *PlayerName = gtk_editable_get_chars(GTK_EDITABLE(stgam.name), 0, -1);
68 if (*PlayerName && (*PlayerName)[0])
69 return TRUE;
70 else {
71 GtkMessageBox(stgam.dialog,
72 _("You can't start the game without giving a name first!"),
73 _("New Game"), GTK_MESSAGE_WARNING, MB_OK);
74 return FALSE;
75 }
76 }
77
78 static void SetStartGameStatus(gchar *msg)
79 {
80 gtk_label_set_text(GTK_LABEL(stgam.status),
81 msg ? msg : _("Status: Waiting for user input"));
82 }
83
84 #ifdef NETWORKING
85
86
87 static void ReportMetaConnectError(GError *err)
88 {
89 char *str = g_strdup_printf(_("Status: ERROR: %s"), err->message);
90 SetStartGameStatus(str);
91 g_free(str);
92 }
93
94 /* Called by glib when we get action on a multi socket */
95 static gboolean glib_socket(GIOChannel *ch, GIOCondition condition,
96 gpointer data)
97 {
98 CurlConnection *g = (CurlConnection*) data;
99 int still_running;
100 GError *err = NULL;
101 int fd = g_io_channel_unix_get_fd(ch);
102 int action =
103 ((condition & G_IO_IN) ? CURL_CSELECT_IN : 0) |
104 ((condition & G_IO_OUT) ? CURL_CSELECT_OUT : 0);
105
106 CurlConnectionSocketAction(g, fd, action, &still_running, &err);
107 if (!err && still_running) {
108 return TRUE;
109 } else {
110 if (g->timer_event) {
111 dp_g_source_remove(g->timer_event);
112 g->timer_event = 0;
113 }
114 if (!err)
115 HandleWaitingMetaServerData(stgam.MetaConn, &stgam.NewMetaList, &err);
116 if (err) {
117 ReportMetaConnectError(err);
118 g_error_free(err);
119 } else {
120 SetStartGameStatus(NULL);
121 }
122
123 CloseCurlConnection(stgam.MetaConn);
124 FillMetaServerList(TRUE);
125 return FALSE;
126 }
127 }
128
129 static gboolean glib_timeout(gpointer userp)
130 {
131 CurlConnection *g = userp;
132 GError *err = NULL;
133 int still_running;
134 if (!CurlConnectionSocketAction(g, CURL_SOCKET_TIMEOUT, 0, &still_running,
135 &err)) {
136 ReportMetaConnectError(err);
137 g_error_free(err);
138 }
139 g->timer_event = 0;
140 return G_SOURCE_REMOVE;
141 }
142
143 static void ConnectError(void)
144 {
145 GString *neterr;
146 gchar *text;
147 LastError *error;
148
149 error = stgam.play->NetBuf.error;
150
151 neterr = g_string_new("");
152
153 if (error) {
154 g_string_assign_error(neterr, error);
155 } else {
156 g_string_assign(neterr, _("Connection closed by remote host"));
157 }
158
159 /* Error: GTK+ client could not connect to the given dopewars server */
160 text = g_strdup_printf(_("Status: Could not connect (%s)"), neterr->str);
161
162 SetStartGameStatus(text);
163 g_free(text);
164 g_string_free(neterr, TRUE);
165 }
166
167 void FinishServerConnect(gboolean ConnectOK)
168 {
169 if (ConnectOK) {
170 Client = Network = TRUE;
171 gtk_widget_destroy(stgam.dialog);
172 GuiStartGame();
173 } else {
174 ConnectError();
175 }
176 }
177
178 static void DoConnect(void)
179 {
180 gchar *text;
181 NetworkBuffer *NetBuf;
182 NBStatus oldstatus;
183 NBSocksStatus oldsocks;
184
185 NetBuf = &stgam.play->NetBuf;
186
187 /* Message displayed during the attempted connect to a dopewars server */
188 text = g_strdup_printf(_("Status: Attempting to contact %s..."),
189 ServerName);
190 SetStartGameStatus(text);
191 g_free(text);
192
193 /* Terminate any existing connection attempts */
194 ShutdownNetworkBuffer(NetBuf);
195 if (stgam.MetaConn->running) {
196 CloseCurlConnection(stgam.MetaConn);
197 }
198
199 oldstatus = NetBuf->status;
200 oldsocks = NetBuf->sockstat;
201 if (StartNetworkBufferConnect(NetBuf, NULL, ServerName, Port)) {
202 DisplayConnectStatus(oldstatus, oldsocks);
203 SetNetworkBufferUserPasswdFunc(NetBuf, SocksAuthDialog, NULL);
204 SetNetworkBufferCallBack(NetBuf, stgam.sockstat, NULL);
205 } else {
206 ConnectError();
207 }
208 }
209
210 static void ConnectToServer(GtkWidget *widget, gpointer data)
211 {
212 gchar *text;
213
214 g_free(ServerName);
215 ServerName = gtk_editable_get_chars(GTK_EDITABLE(stgam.hostname),
216 0, -1);
217 text = gtk_editable_get_chars(GTK_EDITABLE(stgam.port), 0, -1);
218 Port = atoi(text);
219 g_free(text);
220
221 if (GetStartGamePlayerName(&stgam.play->Name)) {
222 DoConnect();
223 }
224 }
225
226 /* Columns in metaserver list */
227 enum {
228 META_COL_SERVER = 0,
229 META_COL_PORT,
230 META_COL_VERSION,
231 META_COL_PLAYERS,
232 META_COL_COMMENT,
233 META_NUM_COLS
234 };
235
236 static void FillMetaServerList(gboolean UseNewList)
237 {
238 GtkWidget *metaserv;
239 GtkListStore *store;
240 ServerData *ThisServer;
241 GtkTreeIter iter;
242 GSList *ListPt;
243
244 if (UseNewList && !stgam.NewMetaList)
245 return;
246
247 metaserv = stgam.metaserv;
248 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(metaserv)));
249
250 gtk_list_store_clear(store);
251
252 if (UseNewList) {
253 ClearServerList(&MetaList);
254 MetaList = stgam.NewMetaList;
255 stgam.NewMetaList = NULL;
256 }
257
258 for (ListPt = MetaList; ListPt; ListPt = g_slist_next(ListPt)) {
259 char *players;
260 ThisServer = (ServerData *)(ListPt->data);
261 if (ThisServer->CurPlayers == -1) {
262 /* Displayed if we don't know how many players are logged on to a
263 server */
264 players = _("Unknown");
265 } else {
266 /* e.g. "5 of 20" means 5 players are logged on to a server, out of
267 a maximum of 20 */
268 players = g_strdup_printf(_("%d of %d"), ThisServer->CurPlayers,
269 ThisServer->MaxPlayers);
270 }
271 gtk_list_store_append(store, &iter);
272 gtk_list_store_set(store, &iter, META_COL_SERVER, ThisServer->Name,
273 META_COL_PORT, ThisServer->Port,
274 META_COL_VERSION, ThisServer->Version,
275 META_COL_PLAYERS, players,
276 META_COL_COMMENT, ThisServer->Comment, -1);
277 if (ThisServer->CurPlayers != -1)
278 g_free(players);
279 }
280 }
281
282 void DisplayConnectStatus(NBStatus oldstatus, NBSocksStatus oldsocks)
283 {
284 NBStatus status;
285 NBSocksStatus sockstat;
286 gchar *text;
287
288 status = stgam.play->NetBuf.status;
289 sockstat = stgam.play->NetBuf.sockstat;
290 if (oldstatus == status && sockstat == oldsocks)
291 return;
292
293 switch (status) {
294 case NBS_PRECONNECT:
295 break;
296 case NBS_SOCKSCONNECT:
297 switch (sockstat) {
298 case NBSS_METHODS:
299 /* Tell the user that we've successfully connected to a SOCKS server,
300 and are now ready to tell it to initiate the "real" connection */
301 text = g_strdup_printf(_("Status: Connected to SOCKS server %s..."),
302 Socks.name);
303 SetStartGameStatus(text);
304 g_free(text);
305 break;
306 case NBSS_USERPASSWD:
307 /* Tell the user that the SOCKS server is asking us for a username
308 and password */
309 SetStartGameStatus(_("Status: Authenticating with SOCKS server"));
310 break;
311 case NBSS_CONNECT:
312 text =
313 /* Tell the user that all necessary SOCKS authentication has been
314 completed, and now we're going to try to have it connect to
315 the final destination */
316 g_strdup_printf(_("Status: Asking SOCKS for connect to %s..."),
317 ServerName);
318 SetStartGameStatus(text);
319 g_free(text);
320 break;
321 }
322 break;
323 case NBS_CONNECTED:
324 break;
325 }
326 }
327
328 static void UpdateMetaServerList(GtkWidget *widget)
329 {
330 gchar *text;
331 GError *tmp_error = NULL;
332
333 /* Terminate any existing connection attempts */
334 ShutdownNetworkBuffer(&stgam.play->NetBuf);
335 if (stgam.MetaConn->running) {
336 CloseCurlConnection(stgam.MetaConn);
337 }
338
339 ClearServerList(&stgam.NewMetaList);
340
341 /* Message displayed during the attempted connect to the metaserver */
342 text = g_strdup_printf(_("Status: Attempting to contact %s..."),
343 MetaServer.URL);
344 SetStartGameStatus(text);
345 g_free(text);
346
347 if (!OpenMetaHttpConnection(stgam.MetaConn, &tmp_error)) {
348 text = g_strdup_printf(_("Status: ERROR: %s"), tmp_error->message);
349 g_error_free(tmp_error);
350 SetStartGameStatus(text);
351 g_free(text);
352 }
353 }
354
355 static void MetaServerConnect(GtkWidget *widget, gpointer data)
356 {
357 GtkTreeSelection *treesel;
358 GtkTreeModel *model;
359 GtkTreeIter iter;
360
361 treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(stgam.metaserv));
362
363 if (gtk_tree_selection_get_selected(treesel, &model, &iter)) {
364 gchar *name;
365 gtk_tree_model_get(model, &iter, META_COL_SERVER, &name,
366 META_COL_PORT, &Port, -1);
367 AssignName(&ServerName, name);
368 g_free(name);
369
370 if (GetStartGamePlayerName(&stgam.play->Name)) {
371 DoConnect();
372 }
373 }
374 }
375 #endif /* NETWORKING */
376
377 static void StartSinglePlayer(GtkWidget *widget, gpointer data)
378 {
379 WantAntique =
380 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(stgam.antique));
381 if (!GetStartGamePlayerName(&stgam.play->Name))
382 return;
383 GuiStartGame();
384 gtk_widget_destroy(stgam.dialog);
385 }
386
387 static void CloseNewGameDia(GtkWidget *widget, gpointer data)
388 {
389 #ifdef NETWORKING
390 /* Terminate any existing connection attempts */
391 if (stgam.play->NetBuf.status != NBS_CONNECTED) {
392 ShutdownNetworkBuffer(&stgam.play->NetBuf);
393 }
394 if (stgam.MetaConn) {
395 CloseCurlConnection(stgam.MetaConn);
396 stgam.MetaConn = NULL;
397 }
398 ClearServerList(&stgam.NewMetaList);
399 #endif
400
401 /* Remember which tab we chose for the next time we use this dialog */
402 NewGameType = gtk_notebook_get_current_page(GTK_NOTEBOOK(stgam.notebook));
403 }
404
405 #ifdef NETWORKING
406 static void metalist_changed(GtkTreeSelection *sel, GtkWidget *conn_button)
407 {
408 gtk_widget_set_sensitive(conn_button,
409 gtk_tree_selection_count_selected_rows(sel) > 0);
410 }
411 #endif
412
413 #ifdef NETWORKING
414 static GtkTreeModel *create_metaserver_model(void)
415 {
416 GtkListStore *store;
417
418 store = gtk_list_store_new(META_NUM_COLS, G_TYPE_STRING, G_TYPE_UINT,
419 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
420 return GTK_TREE_MODEL(store);
421 }
422
423 static GtkWidget *create_metaserver_view(GtkWidget **pack_widg)
424 {
425 int i;
426 GtkWidget *view;
427 GtkTreeModel *model;
428 GtkCellRenderer *renderer;
429 GtkTreeViewColumn *col;
430 gchar *server_titles[META_NUM_COLS];
431 gboolean expand[META_NUM_COLS];
432
433 /* Column titles of metaserver information */
434 server_titles[0] = _("Server"); expand[0] = TRUE;
435 server_titles[1] = _("Port"); expand[1] = FALSE;
436 server_titles[2] = _("Version"); expand[2] = FALSE;
437 server_titles[3] = _("Players"); expand[3] = FALSE;
438 server_titles[4] = _("Comment"); expand[4] = TRUE;
439
440 view = gtk_scrolled_tree_view_new(pack_widg);
441 renderer = gtk_cell_renderer_text_new();
442 for (i = 0; i < META_NUM_COLS; ++i) {
443 col = gtk_tree_view_column_new_with_attributes(
444 server_titles[i], renderer, "text", i, NULL);
445 gtk_tree_view_column_set_resizable(col, TRUE);
446 gtk_tree_view_column_set_expand(col, expand[i]);
447 gtk_tree_view_insert_column(GTK_TREE_VIEW(view), col, -1);
448 }
449 model = create_metaserver_model();
450 gtk_tree_view_set_model(GTK_TREE_VIEW(view), model);
451 /* Tree view keeps a reference, so we can drop ours */
452 g_object_unref(model);
453 return view;
454 }
455 #endif
456
457 static void set_initial_player_name(GtkEntry *entry, Player *play)
458 {
459 char *name = GetPlayerName(play);
460 if (*name) {
461 gtk_entry_set_text(entry, name);
462 } else {
463 /* If name is blank, use the first word from the user's full login name */
464 char *firstspace;
465 name = g_strdup(g_get_real_name());
466 g_strstrip(name);
467 firstspace = strchr(name, ' ');
468 if (firstspace) {
469 *firstspace = '\0';
470 }
471 /* "Unknown" is returned from g_get_real_name() on error */
472 gtk_entry_set_text(entry, strcmp(name, "Unknown") == 0 ? "" : name);
473 g_free(name);
474 }
475 }
476
477 #ifdef NETWORKING
478 void NewGameDialog(Player *play, NBCallBack sockstat, CurlConnection *MetaConn)
479 #else
480 void NewGameDialog(Player *play)
481 #endif
482 {
483 GtkWidget *vbox, *vbox2, *hbox, *label, *entry, *notebook;
484 GtkWidget *button, *dialog;
485 GtkAccelGroup *accel_group;
486 #if GTK_MAJOR_VERSION == 2
487 guint AccelKey;
488 #endif
489
490 #ifdef NETWORKING
491 GtkWidget *clist, *scrollwin, *grid, *hbbox, *defbutton;
492 GtkTreeSelection *treesel;
493 gchar *ServerEntry, *text;
494 gboolean UpdateMeta = FALSE;
495 SetCurlCallback(MetaConn, glib_timeout, glib_socket);
496
497 stgam.MetaConn = MetaConn;
498 stgam.NewMetaList = NULL;
499 stgam.sockstat = sockstat;
500
501 #endif /* NETWORKING */
502
503 stgam.play = play;
504 stgam.dialog = dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
505 g_signal_connect(G_OBJECT(dialog), "destroy",
506 G_CALLBACK(CloseNewGameDia), NULL);
507
508 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
509 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(MainWindow));
510 #ifdef NETWORKING
511 gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 300);
512 #endif
513 accel_group = gtk_accel_group_new();
514
515 /* Title of 'New Game' dialog */
516 gtk_window_set_title(GTK_WINDOW(dialog), _("New Game"));
517 my_set_dialog_position(GTK_WINDOW(dialog));
518 gtk_container_set_border_width(GTK_CONTAINER(dialog), 7);
519 gtk_window_add_accel_group(GTK_WINDOW(dialog), accel_group);
520
521 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 7);
522 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 7);
523
524 label = gtk_label_new("");
525
526 #if GTK_MAJOR_VERSION == 2
527 AccelKey = gtk_label_parse_uline(GTK_LABEL(label),
528 #else
529 gtk_label_set_text_with_mnemonic(GTK_LABEL(label),
530 #endif
531 /* Prompt for player's name in 'New
532 Game' dialog */
533 _("Hey dude, what's your _name?"));
534 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
535
536 entry = stgam.name = gtk_entry_new();
537 #if GTK_MAJOR_VERSION == 2
538 gtk_widget_add_accelerator(entry, "grab-focus", accel_group, AccelKey,
539 GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);
540 #else
541 gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
542 #endif
543 set_initial_player_name(GTK_ENTRY(entry), stgam.play);
544 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
545
546 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
547
548 notebook = stgam.notebook = gtk_notebook_new();
549
550 #ifdef NETWORKING
551 vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 7);
552 gtk_container_set_border_width(GTK_CONTAINER(vbox2), 8);
553 grid = dp_gtk_grid_new(2, 2, FALSE);
554 gtk_grid_set_row_spacing(GTK_GRID(grid), 4);
555 gtk_grid_set_column_spacing(GTK_GRID(grid), 4);
556
557 /* Prompt for hostname to connect to in GTK+ new game dialog */
558 label = gtk_label_new(_("Host name"));
559
560 dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1, FALSE);
561 entry = stgam.hostname = gtk_entry_new();
562
563 ServerEntry = "localhost";
564 if (g_ascii_strncasecmp(ServerName, SN_META, strlen(SN_META)) == 0) {
565 NewGameType = 2;
566 UpdateMeta = TRUE;
567 } else if (g_ascii_strncasecmp(ServerName, SN_PROMPT, strlen(SN_PROMPT)) == 0)
568 NewGameType = 0;
569 else if (g_ascii_strncasecmp(ServerName, SN_SINGLE, strlen(SN_SINGLE)) == 0)
570 NewGameType = 1;
571 else
572 ServerEntry = ServerName;
573
574 gtk_entry_set_text(GTK_ENTRY(entry), ServerEntry);
575 dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 0, 1, 1, TRUE);
576 label = gtk_label_new(_("Port"));
577 dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1, FALSE);
578 entry = stgam.port = gtk_entry_new();
579 text = g_strdup_printf("%d", Port);
580 gtk_entry_set_text(GTK_ENTRY(entry), text);
581 g_free(text);
582 dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 1, 1, 1, TRUE);
583
584 gtk_box_pack_start(GTK_BOX(vbox2), grid, FALSE, FALSE, 0);
585
586 button = gtk_button_new_with_label("");
587 /* Button to connect to a named dopewars server */
588 SetAccelerator(button, _("_Connect"), button, "clicked", accel_group, TRUE);
589 g_signal_connect(G_OBJECT(button), "clicked",
590 G_CALLBACK(ConnectToServer), NULL);
591 gtk_box_pack_start(GTK_BOX(vbox2), button, FALSE, FALSE, 0);
592 gtk_widget_set_can_default(button, TRUE);
593 defbutton = button;
594
595 label = gtk_label_new(_("Server"));
596 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, label);
597 #endif /* NETWORKING */
598
599 vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 7);
600 gtk_container_set_border_width(GTK_CONTAINER(vbox2), 8);
601 stgam.antique = gtk_check_button_new_with_label("");
602
603 /* Checkbox to activate 'antique mode' in single-player games */
604 SetAccelerator(stgam.antique, _("_Antique mode"), stgam.antique,
605 "clicked", accel_group, TRUE);
606 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(stgam.antique),
607 WantAntique);
608 gtk_box_pack_start(GTK_BOX(vbox2), stgam.antique, FALSE, FALSE, 0);
609 button = gtk_button_new_with_label("");
610
611 /* Button to start a new single-player (standalone, non-network) game */
612 SetAccelerator(button, _("_Start single-player game"), button,
613 "clicked", accel_group, TRUE);
614
615 g_signal_connect(G_OBJECT(button), "clicked",
616 G_CALLBACK(StartSinglePlayer), NULL);
617 gtk_box_pack_start(GTK_BOX(vbox2), button, FALSE, FALSE, 0);
618 /* Title of 'New Game' dialog notebook tab for single-player mode */
619 label = gtk_label_new(_("Single player"));
620 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, label);
621
622 #ifdef NETWORKING
623 vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 7);
624 gtk_container_set_border_width(GTK_CONTAINER(vbox2), 8);
625
626 clist = stgam.metaserv = create_metaserver_view(&scrollwin);
627 gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(clist), FALSE);
628 gtk_tree_selection_set_mode(
629 gtk_tree_view_get_selection(GTK_TREE_VIEW(clist)), GTK_SELECTION_SINGLE);
630
631 gtk_box_pack_start(GTK_BOX(vbox2), scrollwin, TRUE, TRUE, 0);
632
633 hbbox = my_hbbox_new();
634
635 /* Button to update metaserver information */
636 button = gtk_button_new_with_mnemonic(_("_Refresh"));
637 g_signal_connect(G_OBJECT(button), "clicked",
638 G_CALLBACK(UpdateMetaServerList), NULL);
639 my_gtk_box_pack_start_defaults(GTK_BOX(hbbox), button);
640
641 button = gtk_button_new_with_label("");
642 SetAccelerator(button, _("_Connect"), button, "clicked", accel_group, TRUE);
643 g_signal_connect(G_OBJECT(button), "clicked",
644 G_CALLBACK(MetaServerConnect), NULL);
645 gtk_widget_set_sensitive(button, FALSE);
646 treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(clist));
647 g_signal_connect(G_OBJECT(treesel), "changed", G_CALLBACK(metalist_changed),
648 button);
649 my_gtk_box_pack_start_defaults(GTK_BOX(hbbox), button);
650
651 gtk_box_pack_start(GTK_BOX(vbox2), hbbox, FALSE, FALSE, 0);
652
653 /* Title of Metaserver notebook tab in New Game dialog */
654 label = gtk_label_new(_("Metaserver"));
655 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, label);
656 #endif /* NETWORKING */
657
658 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
659
660 /* Caption of status label in New Game dialog before anything has
661 * happened */
662 label = stgam.status = gtk_label_new("");
663 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
664
665 gtk_container_add(GTK_CONTAINER(stgam.dialog), vbox);
666
667 gtk_widget_grab_focus(stgam.name);
668 #ifdef NETWORKING
669 if (UpdateMeta) {
670 UpdateMetaServerList(NULL);
671 } else {
672 FillMetaServerList(FALSE);
673 }
674 #endif
675
676 SetStartGameStatus(NULL);
677 gtk_widget_show_all(dialog);
678 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), NewGameType);
679 #ifdef NETWORKING
680 gtk_widget_grab_default(defbutton);
681 #endif
682 }
683
684 #ifdef NETWORKING
685 static void OKSocksAuth(GtkWidget *widget, GtkWidget *window)
686 {
687 g_object_set_data(G_OBJECT(window), "authok", GINT_TO_POINTER(TRUE));
688 gtk_widget_destroy(window);
689 }
690
691 static void DestroySocksAuth(GtkWidget *window, gpointer data)
692 {
693 GtkWidget *userentry, *passwdentry;
694 gchar *username = NULL, *password = NULL;
695 gpointer authok;
696 NetworkBuffer *netbuf;
697
698 authok = g_object_get_data(G_OBJECT(window), "authok");
699 userentry =
700 (GtkWidget *)g_object_get_data(G_OBJECT(window), "username");
701 passwdentry =
702 (GtkWidget *)g_object_get_data(G_OBJECT(window), "password");
703 netbuf =
704 (NetworkBuffer *)g_object_get_data(G_OBJECT(window), "netbuf");
705
706 g_assert(userentry && passwdentry && netbuf);
707
708 if (authok) {
709 username = gtk_editable_get_chars(GTK_EDITABLE(userentry), 0, -1);
710 password = gtk_editable_get_chars(GTK_EDITABLE(passwdentry), 0, -1);
711 }
712
713 SendSocks5UserPasswd(netbuf, username, password);
714 g_free(username);
715 g_free(password);
716 }
717
718 static void SocksAuthDialog(NetworkBuffer *netbuf, gpointer data)
719 {
720 GtkWidget *window, *button, *hsep, *vbox, *label, *entry, *grid, *hbbox;
721 GtkAccelGroup *accel_group;
722
723 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
724 accel_group = gtk_accel_group_new();
725 gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
726
727 g_signal_connect(G_OBJECT(window), "destroy",
728 G_CALLBACK(DestroySocksAuth), NULL);
729 g_object_set_data(G_OBJECT(window), "netbuf", (gpointer)netbuf);
730
731 /* Title of dialog for authenticating with a SOCKS server */
732 gtk_window_set_title(GTK_WINDOW(window),
733 _("SOCKS Authentication Required"));
734 my_set_dialog_position(GTK_WINDOW(window));
735
736 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
737 gtk_window_set_transient_for(GTK_WINDOW(window),
738 GTK_WINDOW(MainWindow));
739 gtk_container_set_border_width(GTK_CONTAINER(window), 7);
740
741 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 7);
742
743 grid = dp_gtk_grid_new(2, 2, FALSE);
744 gtk_grid_set_row_spacing(GTK_GRID(grid), 10);
745 gtk_grid_set_column_spacing(GTK_GRID(grid), 5);
746
747 label = gtk_label_new("User name:");
748 dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1, FALSE);
749
750 entry = gtk_entry_new();
751 g_object_set_data(G_OBJECT(window), "username", (gpointer)entry);
752 dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 0, 1, 1, TRUE);
753
754 label = gtk_label_new("Password:");
755 dp_gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1, FALSE);
756
757 entry = gtk_entry_new();
758 g_object_set_data(G_OBJECT(window), "password", (gpointer)entry);
759
760 #ifdef HAVE_FIXED_GTK
761 /* GTK+ versions earlier than 1.2.10 do bad things with this */
762 gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
763 #endif
764
765 dp_gtk_grid_attach(GTK_GRID(grid), entry, 1, 1, 1, 1, TRUE);
766
767 gtk_box_pack_start(GTK_BOX(vbox), grid, TRUE, TRUE, 0);
768
769 hsep = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
770 gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0);
771
772 hbbox = my_hbbox_new();
773
774 button = gtk_button_new_with_mnemonic(_("_OK"));
775 g_signal_connect(G_OBJECT(button), "clicked",
776 G_CALLBACK(OKSocksAuth), (gpointer)window);
777 my_gtk_box_pack_start_defaults(GTK_BOX(hbbox), button);
778
779 button = gtk_button_new_with_mnemonic(_("_Cancel"));
780 g_signal_connect_swapped(G_OBJECT(button), "clicked",
781 G_CALLBACK(gtk_widget_destroy),
782 G_OBJECT(window));
783 my_gtk_box_pack_start_defaults(GTK_BOX(hbbox), button);
784
785 gtk_box_pack_start(GTK_BOX(vbox), hbbox, TRUE, TRUE, 0);
786
787 gtk_container_add(GTK_CONTAINER(window), vbox);
788 gtk_widget_show_all(window);
789 }
790
791 #endif /* NETWORKING */