Crossfire Client, Branch
R11627
|
00001 const char * const rcsid_gtk2_main_c = "$Id: main.c 10739 2008-11-26 19:50:37Z kbulgrien $"; 00002 00003 /* 00004 Crossfire client, a client program for the crossfire program. 00005 00006 Copyright (C) 2005-2007 Mark Wedel & Crossfire Development Team 00007 00008 This program is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 2 of the License, or 00011 (at your option) any later version. 00012 00013 This program is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with this program; if not, write to the Free Software 00020 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00021 00022 The author can be reached via e-mail to crossfire@metalforge.org 00023 */ 00024 00033 #ifdef HAVE_CONFIG_H 00034 # include <config.h> 00035 #endif 00036 00037 #ifdef WIN32 00038 #include <windows.h> 00039 #endif 00040 #include <gtk/gtk.h> 00041 #include <glade/glade.h> 00042 #include <stdio.h> 00043 #include <errno.h> 00044 #ifndef WIN32 00045 #include <signal.h> 00046 #endif 00047 00048 #include "main.h" 00049 #include "client.h" 00050 #include "image.h" 00051 #include "gtk2proto.h" 00052 #include "script.h" 00053 #include "metaserver.h" 00054 #include "mapdata.h" 00055 00056 GtkWidget *window_root, *magic_map; 00057 GladeXML *dialog_xml, *window_xml; 00058 00059 /* Sets up the basic colors. */ 00060 const char * const colorname[NUM_COLORS] = { 00061 "Black", /* 0 */ 00062 "White", /* 1 */ 00063 "Navy", /* 2 */ 00064 "Red", /* 3 */ 00065 "Orange", /* 4 */ 00066 "DodgerBlue", /* 5 */ 00067 "DarkOrange2", /* 6 */ 00068 "SeaGreen", /* 7 */ 00069 "DarkSeaGreen", /* 8 *//* Used for window background color */ 00070 "Grey50", /* 9 */ 00071 "Sienna", /* 10 */ 00072 "Gold", /* 11 */ 00073 "Khaki" /* 12 */ 00074 }; 00075 00076 /* These are the names as set by the user within the rc file. 00077 * We use lower case to be consistent, but also change the names 00078 * to be more generic instead of specific X11 color names. 00079 */ 00080 const char * const usercolorname[NUM_COLORS] = { 00081 "black", /* 0 */ 00082 "white", /* 1 */ 00083 "darkblue", /* 2 */ 00084 "red", /* 3 */ 00085 "orange", /* 4 */ 00086 "lightblue", /* 5 */ 00087 "darkorange", /* 6 */ 00088 "green", /* 7 */ 00089 "darkgreen", /* 8 *//* Used for window background color */ 00090 "grey", /* 9 */ 00091 "brown", /* 10 */ 00092 "yellow", /* 11 */ 00093 "tan" /* 12 */ 00094 }; 00095 00096 char dialog_xml_file[MAX_BUF] = DIALOG_XML_FILENAME; 00097 char dialog_xml_path[MAX_BUF] = ""; 00098 char window_xml_file[MAX_BUF] = WINDOW_XML_FILENAME; 00103 char window_xml_path[MAX_BUF] = ""; 00104 GdkColor root_color[NUM_COLORS]; 00105 struct timeval timeout; 00106 extern int maxfd; 00107 gint csocket_fd=0; 00108 static uint8 updatekeycodes=FALSE; 00109 extern int time_map_redraw; 00110 00111 #ifdef WIN32 /* Win32 scripting support */ 00112 #define PACKAGE_DATA_DIR "." 00113 00114 int do_scriptout(void) 00115 { 00116 script_process(NULL); 00117 return(TRUE); 00118 } 00119 #endif /* WIN32 */ 00120 00125 int do_timeout(void) 00126 { 00127 if (cpl.showmagic) magic_map_flash_pos(); 00128 if (cpl.spells_updated) update_spell_information(); 00129 if (!tick) { 00130 inventory_tick(); 00131 mapdata_animation(); 00132 } 00133 return TRUE; 00134 } 00135 00139 void client_tick(uint32 tick) 00140 { 00141 inventory_tick(); 00142 mapdata_animation(); 00143 draw_map(0); 00144 } 00145 00150 void cleanup_connection(void) 00151 { 00152 if (csocket_fd) { 00153 gdk_input_remove(csocket_fd); 00154 csocket_fd=0; 00155 gtk_main_quit(); 00156 } 00157 } 00158 00162 void on_window_destroy_event (GtkObject *object, 00163 gpointer user_data) 00164 { 00165 #ifdef WIN32 00166 script_killall(); 00167 #endif 00168 00169 LOG(LOG_INFO, "main.c::client_exit", "Exiting with return value 0."); 00170 exit(0); 00171 } 00172 00176 void do_network(void) 00177 { 00178 fd_set tmp_read; 00179 int pollret; 00180 00181 if (csocket.fd==-1) { 00182 if (csocket_fd) { 00183 gdk_input_remove(csocket_fd); 00184 csocket_fd=0; 00185 gtk_main_quit(); 00186 } 00187 return; 00188 } 00189 00190 FD_ZERO(&tmp_read); 00191 FD_SET(csocket.fd, &tmp_read); 00192 script_fdset(&maxfd,&tmp_read); 00193 pollret = select(maxfd, &tmp_read, NULL, NULL, &timeout); 00194 if (pollret==-1) { 00195 LOG(LOG_WARNING, "main.c::do_network", 00196 "Got errno %d on select call.", errno); 00197 } else if ( pollret>0 ) { 00198 if (FD_ISSET(csocket.fd, &tmp_read)) { 00199 DoClient(&csocket); 00200 #ifndef WIN32 00201 if ( pollret > 1 ) script_process(&tmp_read); 00202 #endif 00203 } else { 00204 script_process(&tmp_read); 00205 } 00206 } 00207 /* DoClient now closes the socket, so we need to check for this here - 00208 * with the socket being closed, this function will otherwise never be 00209 * called again. */ 00210 if (csocket.fd==-1) { 00211 if (csocket_fd) { 00212 gdk_input_remove(csocket_fd); 00213 csocket_fd=0; 00214 gtk_main_quit(); 00215 } 00216 return; 00217 } 00218 #ifdef HAVE_SDL 00219 if (use_config[CONFIG_DISPLAYMODE]==CFG_DM_SDL) sdl_gen_map(FALSE); 00220 else 00221 #endif 00222 #ifdef HAVE_OPENGL 00223 if (use_config[CONFIG_DISPLAYMODE]==CFG_DM_OPENGL) opengl_gen_map(FALSE); 00224 else 00225 #endif 00226 draw_map(FALSE); 00227 00228 draw_lists(); 00229 } 00230 00234 void event_loop(void) 00235 { 00236 gint fleep; 00237 extern int do_timeout(void); 00238 int tag; 00239 00240 if (MAX_TIME==0) { 00241 timeout.tv_sec = 0; 00242 timeout.tv_usec = 0; 00243 } 00244 maxfd = csocket.fd + 1; 00245 00246 if (MAX_TIME!=0) { 00247 timeout.tv_sec = 0;/* MAX_TIME / 1000000;*/ 00248 timeout.tv_usec = 0;/* MAX_TIME % 1000000;*/ 00249 } 00250 00251 fleep = gtk_timeout_add (10, (GtkFunction) do_timeout, NULL); 00252 00253 #ifdef WIN32 00254 gtk_timeout_add (25, (GtkFunction) do_scriptout, NULL); 00255 #endif 00256 00257 if (csocket.fd==-1) { 00258 if (csocket_fd) { 00259 gdk_input_remove(csocket_fd); 00260 csocket_fd=0; 00261 gtk_main_quit(); 00262 } 00263 return; 00264 } 00265 csocket_fd = gdk_input_add ((gint) csocket.fd, 00266 GDK_INPUT_READ, 00267 (GdkInputFunction) do_network, &csocket); 00268 tag = csocket_fd; 00269 00270 gtk_main(); 00271 gtk_timeout_remove(tag); 00272 00273 LOG(LOG_INFO, "main.c::event_loop", 00274 "gtk_main exited, returning from event_loop"); 00275 } 00276 00277 #ifndef WIN32 00278 00286 static void sigpipe_handler(int sig) { 00287 /* ignore that signal for now */ 00288 } 00289 #endif 00290 00298 static void usage(char *progname) 00299 { 00300 puts("Usage of crossfire-client-gtk2:\n"); 00301 puts("-cache - Cache images for future use."); 00302 puts("-nocache - Do not cache images (default action)."); 00303 puts("-darkness - Enables darkness code (default)"); 00304 puts("-nodarkness - Disables darkness code"); 00305 puts("-display <name> - Use <name> instead if DISPLAY environment variable."); 00306 puts("-download_all_faces - Download all needed faces before play starts"); 00307 puts("-echo - Echo the bound commands"); 00308 puts("-noecho - Do not echo the bound commands (default)"); 00309 puts("-faceset <name> - Use faceset <name> if available"); 00310 puts("-fasttcpsend - Send data immediately to server, may increase bandwidth"); 00311 puts("-nofasttcpsend - Disables fasttcpsend"); 00312 puts("-fog - Enable fog of war code"); 00313 puts("-help - Display this message."); 00314 puts("-loglevel <val> - Set default logging level (0 is most verbose)"); 00315 puts("-iconscale %% - Set icon scale percentage"); 00316 puts("-mapscale %% - Set map scale percentage"); 00317 puts("-mapsize xXy - Set the mapsize to be X by Y spaces. (default 11x11)"); 00318 puts("-splash - Display the splash screen (default)"); 00319 puts("-nosplash - Don't display the splash screen (startup logo)"); 00320 puts("-opengl - Use opengl drawing code"); 00321 puts("-pixmap - Use pixmap drawing code"); 00322 puts("-port <number> - Use port <number> instead of the standard port number"); 00323 puts("-sdl - Use sdl for drawing png (may not work on all hardware"); 00324 puts("-server <name> - Connect to <name> instead of localhost."); 00325 puts("-showicon - Print status icons in inventory window"); 00326 puts("-smooth - Enable smooth"); 00327 puts("-nosmooth - Disable smooth (default)"); 00328 puts("-sound - Enable sound output (default)."); 00329 puts("-nosound - Disable sound output."); 00330 puts("-sound_server <path> - Executable to use to play sounds."); 00331 puts("-resists <val> - Control look of resistances."); 00332 puts("-split - Use split windows."); 00333 puts("-splitinfo - Use two information windows, segregated by information type."); 00334 puts("-timemapredraw - Print out timing information for map generation"); 00335 puts("-triminfowindow - Trims size of information window(s)"); 00336 puts("-notriminfowindow - Do not trims size of information window(s) (default)"); 00337 puts("-updatekeycodes - Update the saved bindings for this keyboard."); 00338 puts("-window_xml <file> - Glade Designer client UI layout XML file."); 00339 puts("-dialog_xml <file> - Glade Designer popup dialog XML file."); 00340 00341 exit(0); 00342 } 00343 00350 int parse_args(int argc, char **argv) 00351 { 00352 int on_arg=1; 00353 char *display_name=""; 00354 00355 load_defaults(); 00356 00357 #ifndef WIN32 00358 strcpy(VERSION_INFO,"GTK V2 Unix Client " FULL_VERSION); 00359 #else 00360 strcpy(VERSION_INFO,"GTK V2 Win32 Client " FULL_VERSION); 00361 #endif 00362 /* 00363 * Set this global so we get skill experience - gtk client can display 00364 * it, so lets get the info. 00365 */ 00366 want_skill_exp=1; 00367 for (on_arg=1; on_arg<argc; on_arg++) { 00368 if (!strcmp(argv[on_arg], "-cache")) { 00369 want_config[CONFIG_CACHE]= TRUE; 00370 continue; 00371 } else if (!strcmp(argv[on_arg], "-nocache")) { 00372 want_config[CONFIG_CACHE]= FALSE; 00373 continue; 00374 } else if (!strcmp(argv[on_arg], "-darkness")) { 00375 want_config[CONFIG_DARKNESS]= TRUE; 00376 continue; 00377 } else if (!strcmp(argv[on_arg], "-nodarkness")) { 00378 want_config[CONFIG_DARKNESS]= FALSE; 00379 continue; 00380 } else if (!strcmp(argv[on_arg], "-display")) { 00381 if (++on_arg == argc) { 00382 LOG(LOG_WARNING, "main.c::init_windows", 00383 "-display requires a display name"); 00384 return 1; 00385 } 00386 display_name = argv[on_arg]; 00387 continue; 00388 } else if (!strcmp(argv[on_arg], "-download_all_faces")) { 00389 want_config[CONFIG_DOWNLOAD]= TRUE; 00390 continue; 00391 } else if (!strcmp(argv[on_arg], "-echo")) { 00392 want_config[CONFIG_ECHO]= TRUE; 00393 continue; 00394 } else if (!strcmp(argv[on_arg], "-noecho")) { 00395 want_config[CONFIG_ECHO]= FALSE; 00396 continue; 00397 } else if (!strcmp(argv[on_arg], "-faceset")) { 00398 if (++on_arg == argc) { 00399 LOG(LOG_WARNING, "main.c::init_windows", 00400 "-faceset requires a faceset name/number"); 00401 return 1; 00402 } 00403 face_info.want_faceset = argv[on_arg]; 00404 continue; 00405 } else if (!strcmp(argv[on_arg], "-fog")) { 00406 want_config[CONFIG_FOGWAR]= TRUE; 00407 continue; 00408 } else if (!strcmp(argv[on_arg], "-nofog")) { 00409 want_config[CONFIG_FOGWAR]= FALSE; 00410 continue; 00411 } else if (!strcmp(argv[on_arg], "-help")) { 00412 usage(argv[0]); 00413 continue; 00414 } else if (!strcmp(argv[on_arg], "-iconscale")) { 00415 if (++on_arg == argc) { 00416 LOG(LOG_WARNING, "main.c::init_windows", 00417 "-iconscale requires a percentage value"); 00418 return 1; 00419 } 00420 want_config[CONFIG_ICONSCALE] = atoi(argv[on_arg]); 00421 if (want_config[CONFIG_ICONSCALE] < 25 || want_config[CONFIG_ICONSCALE]>200) { 00422 LOG(LOG_WARNING, "main.c::init_windows", 00423 "Valid range for -iconscale is 25 through 200"); 00424 want_config[CONFIG_ICONSCALE]=100; 00425 return 1; 00426 } 00427 continue; 00428 } else if (!strcmp(argv[on_arg], "-mapscale")) { 00429 if (++on_arg == argc) { 00430 LOG(LOG_WARNING, "main.c::init_windows", 00431 "-mapscale requires a percentage value"); 00432 return 1; 00433 } 00434 want_config[CONFIG_MAPSCALE] = atoi(argv[on_arg]); 00435 if (want_config[CONFIG_MAPSCALE] < 25 || want_config[CONFIG_MAPSCALE]>200) { 00436 LOG(LOG_WARNING, "main.c::init_windows", 00437 "Valid range for -mapscale is 25 through 200"); 00438 want_config[CONFIG_MAPSCALE]=100; 00439 return 1; 00440 } 00441 continue; 00442 } else if (!strcmp(argv[on_arg], "-mapsize")) { 00443 char *cp, x, y=0; 00444 00445 if (++on_arg == argc) { 00446 LOG(LOG_WARNING, "main.c::init_windows", 00447 "-mapsize requires a XxY value"); 00448 return 1; 00449 } 00450 x = atoi(argv[on_arg]); 00451 for (cp = argv[on_arg]; *cp!='\0'; cp++) 00452 if (*cp == 'x' || *cp == 'X') break; 00453 00454 if (*cp == 0) { 00455 LOG(LOG_WARNING, "main.c::init_windows", "-mapsize requires " 00456 "both X and Y values (ie, XxY - note the\nx in between."); 00457 } else { 00458 y = atoi(cp+1); 00459 } 00460 if (x<9 || y<9) { 00461 LOG(LOG_WARNING, "main.c::init_windows", 00462 "Map size must be positive values of at least 9"); 00463 } else if (x>MAP_MAX_SIZE || y>MAP_MAX_SIZE) { 00464 LOG(LOG_WARNING, "main.c::init_windows", "Map size cannot be " 00465 "larger than %d x %d", MAP_MAX_SIZE, MAP_MAX_SIZE); 00466 00467 } else { 00468 want_config[CONFIG_MAPWIDTH]=x; 00469 want_config[CONFIG_MAPHEIGHT]=y; 00470 } 00471 continue; 00472 } else if (!strcmp(argv[on_arg], "-fasttcpsend")) { 00473 want_config[CONFIG_FASTTCP] = TRUE; 00474 continue; 00475 } else if (!strcmp(argv[on_arg], "-nofasttcpsend")) { 00476 want_config[CONFIG_FASTTCP] = FALSE; 00477 continue; 00478 } else if (!strcmp(argv[on_arg], "-opengl")) { 00479 #ifndef HAVE_OPENGL 00480 LOG(LOG_WARNING, "main.c::init_windows", "client not compiled " 00481 "with opengl support. Ignoring -opengl"); 00482 #else 00483 want_config[CONFIG_DISPLAYMODE] = CFG_DM_OPENGL; 00484 #endif 00485 continue; 00486 } else if (!strcmp(argv[on_arg], "-pixmap")) { 00487 want_config[CONFIG_DISPLAYMODE] = CFG_DM_PIXMAP; 00488 } else if (!strcmp(argv[on_arg], "-port")) { 00489 if (++on_arg == argc) { 00490 LOG(LOG_WARNING, "main.c::init_windows", 00491 "-port requires a port number"); 00492 return 1; 00493 } 00494 want_config[CONFIG_PORT] = atoi(argv[on_arg]); 00495 continue; 00496 } else if (!strcmp(argv[on_arg], "-sdl")) { 00497 #ifndef HAVE_SDL 00498 LOG(LOG_WARNING, "main.c::init_windows", 00499 "client not compiled with sdl support. Ignoring -sdl"); 00500 #else 00501 want_config[CONFIG_DISPLAYMODE] = CFG_DM_SDL; 00502 #endif 00503 continue; 00504 } else if (!strcmp(argv[on_arg], "-server")) { 00505 if (++on_arg == argc) { 00506 LOG(LOG_WARNING, "main.c::init_windows", 00507 "-server requires a host name"); 00508 return 1; 00509 } 00510 server = argv[on_arg]; 00511 continue; 00512 } else if (!strcmp(argv[on_arg], "-showicon")) { 00513 want_config[CONFIG_SHOWICON] = TRUE; 00514 continue; 00515 } else if (!strcmp(argv[on_arg], "-smooth")) { 00516 want_config[CONFIG_SMOOTH] = TRUE; 00517 } else if (!strcmp(argv[on_arg], "-nosmooth")) { 00518 want_config[CONFIG_SMOOTH] = FALSE; 00519 } else if (!strcmp(argv[on_arg], "-sound")) { 00520 want_config[CONFIG_SOUND] = TRUE; 00521 continue; 00522 } else if (!strcmp(argv[on_arg], "-nosound")) { 00523 want_config[CONFIG_SOUND] = FALSE; 00524 continue; 00525 } else if (!strcmp(argv[on_arg], "-sound_server")) { 00526 if (++on_arg == argc) { 00527 LOG(LOG_WARNING, "main.c::init_windows", 00528 "-sound_server requires an executable pathname"); 00529 return 1; 00530 } 00531 sound_server = argv[on_arg]; 00532 continue; 00533 } else if (!strcmp(argv[on_arg], "-split")) { 00534 want_config[CONFIG_SPLITWIN]=TRUE; 00535 continue; 00536 } else if (!strcmp(argv[on_arg], "-nosplit")) { 00537 want_config[CONFIG_SPLITWIN]=FALSE; 00538 continue; 00539 } else if (!strcmp(argv[on_arg], "-resists")) { 00540 if (++on_arg == argc) { 00541 LOG(LOG_WARNING, "main.c::init_windows", 00542 "-resists requires a value"); 00543 return 1; 00544 } 00545 want_config[CONFIG_RESISTS]=atoi(argv[on_arg]); 00546 continue; 00547 } else if (!strcmp(argv[on_arg], "-loglevel")) { 00548 extern int MINLOG; 00549 00550 if (++on_arg == argc) { 00551 LOG(LOG_WARNING, "main.c::init_windows", 00552 "-loglevel requires a value"); 00553 return 1; 00554 } 00555 MINLOG = atoi(argv[on_arg]); 00556 continue; 00557 } else if (!strcmp(argv[on_arg], "-splitinfo")) { 00558 want_config[CONFIG_SPLITINFO]=TRUE; 00559 continue; 00560 } else if (!strcmp(argv[on_arg], "-timemapredraw")) { 00561 time_map_redraw=TRUE; 00562 continue; 00563 } else if (!strcmp(argv[on_arg], "-triminfowindow")) { 00564 want_config[CONFIG_TRIMINFO] = TRUE; 00565 continue; 00566 } else if (!strcmp(argv[on_arg], "-notriminfowindow")) { 00567 want_config[CONFIG_TRIMINFO] = FALSE; 00568 continue; 00569 } else if (!strcmp(argv[on_arg], "-updatekeycodes")) { 00570 updatekeycodes=TRUE; 00571 continue; 00572 } else if (!strcmp(argv[on_arg], "-splash")) { 00573 want_config[CONFIG_SPLASH] = TRUE; 00574 continue; 00575 } else if (!strcmp(argv[on_arg], "-nosplash")) { 00576 want_config[CONFIG_SPLASH] = FALSE; 00577 continue; 00578 } else if (!strcmp(argv[on_arg], "-window_xml")) { 00579 if (++on_arg == argc) { 00580 LOG(LOG_WARNING, "main.c::init_windows", 00581 "-window_xml requires a glade xml file name"); 00582 return 1; 00583 } 00584 strncpy (window_xml_path, argv[on_arg], MAX_BUF-1); 00585 continue; 00586 } else if (!strcmp(argv[on_arg], "-dialog_xml")) { 00587 if (++on_arg == argc) { 00588 LOG(LOG_WARNING, "main.c::init_windows", 00589 "-dialog_xml requires a glade xml file name"); 00590 return 1; 00591 } 00592 strncpy (dialog_xml_path, argv[on_arg], MAX_BUF-1); 00593 continue; 00594 } else { 00595 LOG(LOG_WARNING, "main.c::init_windows", 00596 "Do not understand option %s", argv[on_arg]); 00597 usage(argv[0]); 00598 return 1; 00599 } 00600 } 00601 00602 /* 00603 * Move this after the parsing of command line options, since that can 00604 * change the default log level. 00605 */ 00606 LOG(LOG_INFO, "Client Version", VERSION_INFO); 00607 00608 /* Now copy over the values just loaded */ 00609 for (on_arg=0; on_arg<CONFIG_NUMS; on_arg++) { 00610 use_config[on_arg] = want_config[on_arg]; 00611 } 00612 00613 image_size = DEFAULT_IMAGE_SIZE * use_config[CONFIG_ICONSCALE] / 100; 00614 map_image_size = DEFAULT_IMAGE_SIZE * use_config[CONFIG_MAPSCALE] / 100; 00615 map_image_half_size = DEFAULT_IMAGE_SIZE * use_config[CONFIG_MAPSCALE] / 200; 00616 if (!use_config[CONFIG_CACHE]) use_config[CONFIG_DOWNLOAD] = FALSE; 00617 00618 mapdata_init(); 00619 00620 return 0; 00621 } 00622 00636 static void error_dialog(char *description, char *information) 00637 { 00638 GtkWidget *dialog; 00639 00640 gtk_init(NULL, NULL); 00641 dialog = 00642 gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, 00643 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Crossfire %s\n%s", 00644 VERSION_INFO, description); 00645 gtk_message_dialog_format_secondary_markup(GTK_MESSAGE_DIALOG(dialog), 00646 "%s", information); 00647 gtk_dialog_run(GTK_DIALOG(dialog)); 00648 gtk_widget_destroy(dialog); 00649 } 00650 00657 int 00658 main (int argc, char *argv[]) 00659 { 00660 int i, got_one=0; 00661 static char file_cache[ MAX_BUF ]; 00662 GdkGeometry geometry; 00663 GladeXML *xml_tree; 00664 00665 #ifdef ENABLE_NLS 00666 bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); 00667 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); 00668 textdomain (GETTEXT_PACKAGE); 00669 #endif 00670 00671 gtk_set_locale (); 00672 gtk_init (&argc, &argv); 00673 00674 /* parse_args() has to come after init_client_vars() */ 00675 init_client_vars(); 00676 use_config[CONFIG_MAPWIDTH] = want_config[CONFIG_MAPWIDTH] = 25; 00677 use_config[CONFIG_MAPHEIGHT] = want_config[CONFIG_MAPHEIGHT] = 25; 00678 00679 00680 parse_args(argc, argv); 00681 load_theme(FALSE); 00682 00683 csocket.inbuf.buf=malloc(MAXSOCKBUF); 00684 00685 #ifdef WIN32 /* def WIN32 */ 00686 maxfd = 0; /* This is ignored on win32 platforms */ 00687 00688 /* This is required for sockets to be used under win32 */ 00689 { 00690 WORD Version = 0x0202; 00691 WSADATA wsaData; 00692 00693 if (WSAStartup( Version, &wsaData ) != 0) { 00694 LOG(LOG_CRITICAL, "main.c::main", "Could not load winsock!"); 00695 exit(1); 00696 } 00697 } 00698 #else /* def WIN32 */ 00699 signal(SIGPIPE, sigpipe_handler); 00700 #ifdef HAVE_SYSCONF 00701 maxfd = sysconf(_SC_OPEN_MAX); 00702 #else 00703 maxfd = getdtablesize(); 00704 #endif 00705 #endif /* def WIN32 */ 00706 00707 if (init_sounds() == -1) 00708 use_config[CONFIG_SOUND] = FALSE; 00709 else use_config[CONFIG_SOUND] = TRUE; 00710 00711 /* 00712 * Load Glade XML layout files for the main client window and for the other 00713 * popup dialogs. The popup dialogs must all have the "visible" attribute 00714 * set to "no" so they are not shown initially. 00715 * 00716 * NOTE: glade_init() is implicitly called on glade_xml_new(). 00717 * 00718 * First, load up the common dialogs. If the XML file path is already set, 00719 * it is because a command-line parameter was used to specify it. If not 00720 * set, construct the path to the file from the default path and name 00721 * settings. 00722 */ 00723 if (! dialog_xml_path[0]) { 00724 strncat(dialog_xml_path, XML_PATH_DEFAULT, MAX_BUF-1); 00725 strncat(dialog_xml_path, dialog_xml_file, 00726 MAX_BUF-strlen(dialog_xml_path)-1); 00727 } 00728 dialog_xml = glade_xml_new(dialog_xml_path, NULL, NULL); 00729 if (! dialog_xml) { 00730 sprintf(dialog_xml_file, "Dialog layout file load failed"); 00731 error_dialog(dialog_xml_file, dialog_xml_path); 00732 exit(-1); 00733 } 00734 00735 /* 00736 * Next, load up the root window. If the XML file path is already set, it 00737 * is because a command-line parameter was used to specify it. If not set, 00738 * construct the path to the file from the default settings, and any values 00739 * loaded from the gdefaults2 file. 00740 */ 00741 if (! window_xml_path[0]) { 00742 strncat(window_xml_path, XML_PATH_DEFAULT, MAX_BUF-1); 00743 strncat(window_xml_path, window_xml_file, 00744 MAX_BUF-strlen(window_xml_path)-1); 00745 } 00746 window_xml = glade_xml_new(window_xml_path, NULL, NULL); 00747 if (! window_xml) { 00748 sprintf(window_xml_file, "Main window layout file load failed"); 00749 error_dialog(window_xml_file, window_xml_path); 00750 exit(-1); 00751 } 00752 00753 /* Begin connecting signals for the root window loaded by libglade. */ 00754 window_root = glade_xml_get_widget(window_xml, "window_root"); 00755 00756 g_signal_connect_swapped ((gpointer) window_root, "key_press_event", 00757 G_CALLBACK (keyfunc), GTK_OBJECT (window_root)); 00758 g_signal_connect_swapped ((gpointer) window_root, "key_release_event", 00759 G_CALLBACK (keyrelfunc), GTK_OBJECT (window_root)); 00760 g_signal_connect ((gpointer) window_root, "destroy", 00761 G_CALLBACK (on_window_destroy_event), NULL); 00762 00763 /* Purely arbitrary min window size */ 00764 geometry.min_width=640; 00765 geometry.min_height=480; 00766 00767 gtk_window_set_geometry_hints(GTK_WINDOW(window_root), window_root, 00768 &geometry, GDK_HINT_MIN_SIZE); 00769 00770 /* Set up colors before doing the other initialization functions */ 00771 for (i=0; i<NUM_COLORS; i++) { 00772 if ( !gdk_color_parse(colorname[i], &root_color[i])) { 00773 fprintf(stderr, "gdk_color_parse failed (%s)\n",colorname[i]); 00774 } 00775 if ( !gdk_color_alloc (gtk_widget_get_colormap (window_root), 00776 &root_color[i])) { 00777 fprintf(stderr, "gdk_color_alloc failed\n"); 00778 } 00779 } 00780 00781 inventory_init(window_root); 00782 info_init(window_root); 00783 keys_init(window_root); 00784 stats_init(window_root); 00785 config_init(window_root); 00786 pickup_init(window_root); 00787 00788 load_window_positions(window_root); 00789 00790 /* We want this as late as possible in the process. This way, adjustments 00791 * that the widgets make on initialization are not visible - this is most 00792 * important with the inventory widget which has to create the panes and 00793 * fill in the data - if the window_root is shown before that, there is a 00794 * brief glimpse of the glade layout, which, IMO, doesn't look great. 00795 * Also, it should be faster to realize this as later as possible. */ 00796 gtk_widget_show (window_root); 00797 00798 map_init(window_root); 00799 00800 xml_tree = glade_get_widget_tree(GTK_WIDGET(window_root)); 00801 magic_map = glade_xml_get_widget(xml_tree, "drawingarea_magic_map"); 00802 00803 g_signal_connect ((gpointer) magic_map, "expose_event", 00804 G_CALLBACK (on_drawingarea_magic_map_expose_event), NULL); 00805 00806 snprintf( file_cache, MAX_BUF, "%s/.crossfire/servers.cache", getenv( "HOME" ) ); 00807 cached_server_file = file_cache; 00808 00809 init_cache_data(); 00810 00811 /* Loop to connect to server/metaserver and play the game */ 00812 while (1) { 00813 reset_client_vars(); 00814 clear_stat_mapping(); 00815 csocket.inbuf.len=0; 00816 csocket.cs_version=0; 00817 00818 /* 00819 * Perhaps not the best assumption, but we are taking it that if the 00820 * player has not specified a server (ie, server matches compiled in 00821 * default), we use the metaserver. Otherwise, use the server 00822 * provided, bypassing metaserver. Also, if the player has already 00823 * played on a server once (defined by got_one), go to the metaserver. 00824 * That gives them the opportunity to quit the client or select another 00825 * server. We should really add an entry for the last server there 00826 * also. 00827 */ 00828 if (!server || got_one) { 00829 draw_splash(); 00830 metaserver_get_info(meta_server, meta_port); 00831 get_metaserver(); 00832 /* Call this after get_metaserver so one can't do anything 00833 * with the menus at that point. 00834 */ 00835 enable_menu_items(TRUE); 00836 negotiate_connection(use_config[CONFIG_SOUND]); 00837 } else { 00838 enable_menu_items(TRUE); 00839 csocket.fd=init_connection(server, use_config[CONFIG_PORT]); 00840 if (csocket.fd == -1) { /* specified server no longer valid */ 00841 server = NULL; 00842 continue; 00843 } 00844 negotiate_connection(use_config[CONFIG_SOUND]); 00845 } 00846 00847 got_one=1; 00848 00849 event_loop(); 00850 /* 00851 * if event_loop has exited, we most likely of lost our connection, so 00852 * we loop again to establish a new one. 00853 */ 00854 00855 remove_item_inventory(cpl.ob); 00856 /* 00857 * We know the following is the private map structure in item.c. But 00858 * we don't have direct access to it, so we still use locate. 00859 */ 00860 remove_item_inventory(locate_item(0)); 00861 draw_look_list(); 00862 00863 mapdata_reset(); 00864 /* 00865 * Need to reset the images so they match up properly and prevent 00866 * memory leaks. 00867 */ 00868 reset_image_data(); 00869 } 00870 exit(0); /* never reached */ 00871 00872 return 0; 00873 } 00874 00886 void get_window_coord(GtkWidget *win, 00887 int *x,int *y, 00888 int *wx,int *wy, 00889 int *w,int *h) 00890 { 00891 /* Position of a window relative to its parent window. */ 00892 gdk_window_get_geometry (win->window, x, y, w, h, NULL); 00893 /* Position of the window in root window coordinates. */ 00894 gdk_window_get_origin (win->window, wx, wy); 00895 *wx -= *x; 00896 *wy -= *y; 00897 }