Crossfire Client, Branch  R11627
main.c
Go to the documentation of this file.
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 }