newgamedia.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 */