Crossfire Client, Trunk  R18925
/home/leaf/crossfire/client/trunk/gtk-v2/src/main.c
Go to the documentation of this file.
00001 const char * const rcsid_gtk2_main_c = "$Id: main.c 14240 2011-01-12 06:31:21Z mwedel $";
00002 
00003 /*
00004     Crossfire client, a client program for the crossfire program.
00005 
00006     Copyright (C) 2005-2010 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 "client.h"
00049 #include "main.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     info_buffer_tick();                 /* Maintain the info output buffers */
00142     inventory_tick();
00143     mapdata_animation();
00144 
00145     /* If we have new images to display, we need to do a complete redraw
00146      * periodically - to keep performance up, we don't want to do it every
00147      * tick, but every 5 (about half a second) is still pretty fast but should
00148      * also keep reasonable performance.
00149      */
00150     if (have_new_image && !(tick % 5)) {
00151         if (cpl.container)
00152             cpl.container->inv_updated=1;
00153         cpl.ob->inv_updated=1;
00154 
00155         have_new_image=0;
00156         draw_map(1);
00157         draw_lists();
00158     } else {
00159         draw_map(0);
00160     }
00161 }
00162 
00167 void cleanup_connection(void)
00168 {
00169     if (csocket_fd) {
00170         gdk_input_remove(csocket_fd);
00171         csocket_fd=0;
00172         gtk_main_quit();
00173     }
00174 }
00175 
00179 void on_window_destroy_event           (GtkObject        *object,
00180                                         gpointer         user_data)
00181 {
00182 #ifdef WIN32
00183     script_killall();
00184 #endif
00185 
00186     LOG(LOG_INFO, "main.c::client_exit", "Exiting with return value 0.");
00187     exit(0);
00188 }
00189 
00193 void do_network(void)
00194 {
00195     fd_set tmp_read;
00196     int pollret;
00197 
00198     if (csocket.fd==-1) {
00199         if (csocket_fd) {
00200             gdk_input_remove(csocket_fd);
00201             csocket_fd=0;
00202             gtk_main_quit();
00203         }
00204         return;
00205     }
00206 
00207     FD_ZERO(&tmp_read);
00208     FD_SET(csocket.fd, &tmp_read);
00209     script_fdset(&maxfd,&tmp_read);
00210     pollret = select(maxfd, &tmp_read, NULL, NULL, &timeout);
00211     if (pollret==-1) {
00212         LOG(LOG_WARNING, "main.c::do_network",
00213             "Got errno %d on select call.", errno);
00214     } else if ( pollret>0 ) {
00215         if (FD_ISSET(csocket.fd, &tmp_read)) {
00216             DoClient(&csocket);
00217 #ifndef WIN32
00218             if ( pollret > 1 ) script_process(&tmp_read);
00219 #endif
00220         } else {
00221             script_process(&tmp_read);
00222         }
00223     }
00224     /* DoClient now closes the socket, so we need to check for this here -
00225      * with the socket being closed, this function will otherwise never be
00226      * called again. */
00227     if (csocket.fd==-1) {
00228         if (csocket_fd) {
00229             gdk_input_remove(csocket_fd);
00230             csocket_fd=0;
00231             gtk_main_quit();
00232         }
00233         return;
00234     }
00235 #ifdef HAVE_SDL
00236     if (use_config[CONFIG_DISPLAYMODE]==CFG_DM_SDL) sdl_gen_map(FALSE);
00237     else
00238 #endif
00239 #ifdef HAVE_OPENGL
00240     if (use_config[CONFIG_DISPLAYMODE]==CFG_DM_OPENGL) opengl_gen_map(FALSE);
00241     else
00242 #endif
00243         draw_map(FALSE);
00244 
00245     draw_lists();
00246 }
00247 
00251 void event_loop(void)
00252 {
00253     gint fleep;
00254     extern int do_timeout(void);
00255     int tag;
00256 
00257     if (MAX_TIME==0) {
00258         timeout.tv_sec = 0;
00259         timeout.tv_usec = 0;
00260     }
00261     maxfd = csocket.fd + 1;
00262 
00263     if (MAX_TIME!=0) {
00264         timeout.tv_sec = 0;/* MAX_TIME / 1000000;*/
00265         timeout.tv_usec = 0;/* MAX_TIME % 1000000;*/
00266     }
00267 
00268     fleep =  gtk_timeout_add (10, (GtkFunction) do_timeout, NULL);
00269 
00270 #ifdef WIN32
00271     gtk_timeout_add (25, (GtkFunction) do_scriptout, NULL);
00272 #endif
00273 
00274     if (csocket.fd==-1) {
00275         if (csocket_fd) {
00276             gdk_input_remove(csocket_fd);
00277             csocket_fd=0;
00278             gtk_main_quit();
00279         }
00280         return;
00281     }
00282     csocket_fd = gdk_input_add ((gint) csocket.fd,
00283                               GDK_INPUT_READ,
00284                               (GdkInputFunction) do_network, &csocket);
00285     tag = csocket_fd;
00286 
00287     gtk_main();
00288     gtk_timeout_remove(tag);
00289 
00290     LOG(LOG_INFO, "main.c::event_loop",
00291         "gtk_main exited, returning from event_loop");
00292 }
00293 
00294 #ifndef WIN32
00295 
00303 static void sigpipe_handler(int sig) {
00304   /* ignore that signal for now */
00305 }
00306 #endif
00307 
00314 static void usage(char *progname)
00315 {
00316     puts("Usage of crossfire-client-gtk2:\n");
00317     puts("-cache           - Cache images for future use.");
00318     puts("-nocache         - Do not cache images (default action).");
00319     puts("-darkness        - Enables darkness code (default)");
00320     puts("-nodarkness      - Disables darkness code");
00321     puts("-display <name>  - Use <name> instead if DISPLAY environment variable.");
00322     puts("-download_all_faces - Download all needed faces before play starts");
00323     puts("-echo            - Echo the bound commands");
00324     puts("-noecho          - Do not echo the bound commands (default)");
00325     puts("-faceset <name>  - Use faceset <name> if available");
00326     puts("-fasttcpsend     - Send data immediately to server, may increase bandwidth");
00327     puts("-nofasttcpsend   - Disables fasttcpsend");
00328     puts("-fog             - Enable fog of war code");
00329     puts("-help            - Display this message.");
00330     puts("-loglevel <val>  - Set default logging level (0 is most verbose)");
00331     puts("-iconscale %%    - Set icon scale percentage");
00332     puts("-mapscale %%     - Set map scale percentage");
00333     puts("-mapsize xXy     - Set the mapsize to be X by Y spaces. (default 11x11)");
00334     puts("-splash          - Display the splash screen (default)");
00335     puts("-nosplash        - Don't display the splash screen (startup logo)");
00336     puts("-opengl          - Use opengl drawing code");
00337     puts("-pixmap          - Use pixmap drawing code");
00338     puts("-port <number>   - Use port <number> instead of the standard port number");
00339     puts("-sdl             - Use sdl for drawing png (may not work on all hardware");
00340     puts("-server <name>   - Connect to <name> instead of localhost.");
00341     puts("-showicon        - Print status icons in inventory window");
00342     puts("-smooth          - Enable smooth");
00343     puts("-nosmooth        - Disable smooth (default)");
00344     puts("-sound           - Enable sound output (default).");
00345     puts("-nosound         - Disable sound output.");
00346     puts("-sound_server <path> - Executable to use to play sounds.");
00347     puts("-resists <val>   - Control look of resistances.");
00348     puts("-split           - Use split windows.");
00349     puts("-splitinfo       - Use two information windows, segregated by information type.");
00350     puts("-timemapredraw   - Print out timing information for map generation");
00351     puts("-triminfowindow  - Trims size of information window(s)");
00352     puts("-notriminfowindow  - Do not trims size of information window(s) (default)");
00353     puts("-updatekeycodes  - Update the saved bindings for this keyboard.");
00354     puts("-window_xml <file> - Glade Designer client UI layout XML file.");
00355     puts("-dialog_xml <file> - Glade Designer popup dialog XML file.");
00356 
00357     exit(0);
00358 }
00359 
00366 int parse_args(int argc, char **argv)
00367 {
00368     int on_arg=1;
00369     char *display_name="";
00370 
00371     load_defaults();
00372 
00373 #ifndef WIN32
00374     snprintf(VERSION_INFO, MAX_BUF, "GTK V2 Unix Client %s (using %s)", FULL_VERSION, window_xml_file);
00375 #else
00376     snprintf(VERSION_INFO, MAX_BUF, "GTK V2 Win32 Client %s (using %s)", FULL_VERSION, window_xml_file);
00377 #endif
00378     for (on_arg=1; on_arg<argc; on_arg++) {
00379         if (!strcmp(argv[on_arg], "-cache")) {
00380             want_config[CONFIG_CACHE]= TRUE;
00381             continue;
00382         } else if (!strcmp(argv[on_arg], "-nocache")) {
00383             want_config[CONFIG_CACHE]= FALSE;
00384             continue;
00385         } else if (!strcmp(argv[on_arg], "-darkness")) {
00386             want_config[CONFIG_DARKNESS]= TRUE;
00387             continue;
00388         } else if (!strcmp(argv[on_arg], "-nodarkness")) {
00389             want_config[CONFIG_DARKNESS]= FALSE;
00390             continue;
00391         } else if (!strcmp(argv[on_arg], "-display")) {
00392             if (++on_arg == argc) {
00393                 LOG(LOG_WARNING, "main.c::init_windows",
00394                     "-display requires a display name");
00395                 return 1;
00396             }
00397             display_name = argv[on_arg];
00398             continue;
00399         } else if (!strcmp(argv[on_arg], "-download_all_faces")) {
00400             want_config[CONFIG_DOWNLOAD]= TRUE;
00401             continue;
00402         } else if (!strcmp(argv[on_arg], "-echo")) {
00403             want_config[CONFIG_ECHO]= TRUE;
00404             continue;
00405         } else if (!strcmp(argv[on_arg], "-noecho")) {
00406             want_config[CONFIG_ECHO]= FALSE;
00407             continue;
00408         } else if (!strcmp(argv[on_arg], "-faceset")) {
00409             if (++on_arg == argc) {
00410                 LOG(LOG_WARNING, "main.c::init_windows",
00411                     "-faceset requires a faceset name/number");
00412                 return 1;
00413             }
00414             face_info.want_faceset = argv[on_arg];
00415             continue;
00416         } else if (!strcmp(argv[on_arg], "-fog")) {
00417             want_config[CONFIG_FOGWAR]= TRUE;
00418             continue;
00419         } else if (!strcmp(argv[on_arg], "-nofog")) {
00420             want_config[CONFIG_FOGWAR]= FALSE;
00421             continue;
00422         } else if (!strcmp(argv[on_arg], "-help")) {
00423             usage(argv[0]);
00424             continue;
00425         } else if (!strcmp(argv[on_arg], "-iconscale")) {
00426             if (++on_arg == argc) {
00427                 LOG(LOG_WARNING, "main.c::init_windows",
00428                     "-iconscale requires a percentage value");
00429                 return 1;
00430             }
00431             want_config[CONFIG_ICONSCALE] = atoi(argv[on_arg]);
00432             if (want_config[CONFIG_ICONSCALE] < 25 || want_config[CONFIG_ICONSCALE]>200) {
00433                 LOG(LOG_WARNING, "main.c::init_windows",
00434                     "Valid range for -iconscale is 25 through 200");
00435                 want_config[CONFIG_ICONSCALE]=100;
00436                 return 1;
00437             }
00438             continue;
00439         } else if (!strcmp(argv[on_arg], "-mapscale")) {
00440             if (++on_arg == argc) {
00441                 LOG(LOG_WARNING, "main.c::init_windows",
00442                     "-mapscale requires a percentage value");
00443                 return 1;
00444             }
00445             want_config[CONFIG_MAPSCALE] = atoi(argv[on_arg]);
00446             if (want_config[CONFIG_MAPSCALE] < 25 || want_config[CONFIG_MAPSCALE]>200) {
00447                 LOG(LOG_WARNING, "main.c::init_windows",
00448                     "Valid range for -mapscale is 25 through 200");
00449                 want_config[CONFIG_MAPSCALE]=100;
00450                 return 1;
00451             }
00452             continue;
00453         } else if (!strcmp(argv[on_arg], "-mapsize")) {
00454             char *cp, x, y=0;
00455 
00456             if (++on_arg == argc) {
00457                 LOG(LOG_WARNING, "main.c::init_windows",
00458                     "-mapsize requires a XxY value");
00459                 return 1;
00460             }
00461             x = atoi(argv[on_arg]);
00462             for (cp = argv[on_arg]; *cp!='\0'; cp++)
00463                 if (*cp == 'x' || *cp == 'X') break;
00464 
00465             if (*cp == 0) {
00466                 LOG(LOG_WARNING, "main.c::init_windows", "-mapsize requires "
00467                     "both X and Y values (ie, XxY - note the\nx in between.");
00468             } else {
00469                 y = atoi(cp+1);
00470             }
00471             if (x<9 || y<9) {
00472                 LOG(LOG_WARNING, "main.c::init_windows",
00473                     "Map size must be positive values of at least 9");
00474             } else if (x>MAP_MAX_SIZE || y>MAP_MAX_SIZE) {
00475                 LOG(LOG_WARNING, "main.c::init_windows", "Map size cannot be "
00476                     "larger than %d x %d", MAP_MAX_SIZE, MAP_MAX_SIZE);
00477 
00478             } else {
00479                 want_config[CONFIG_MAPWIDTH]=x;
00480                 want_config[CONFIG_MAPHEIGHT]=y;
00481             }
00482             continue;
00483         } else if (!strcmp(argv[on_arg], "-fasttcpsend")) {
00484             want_config[CONFIG_FASTTCP] = TRUE;
00485             continue;
00486         } else if (!strcmp(argv[on_arg], "-nofasttcpsend")) {
00487             want_config[CONFIG_FASTTCP] = FALSE;
00488             continue;
00489         } else if (!strcmp(argv[on_arg], "-opengl")) {
00490 #ifndef HAVE_OPENGL
00491             LOG(LOG_WARNING, "main.c::init_windows", "client not compiled "
00492                 "with opengl support.  Ignoring -opengl");
00493 #else
00494             want_config[CONFIG_DISPLAYMODE] = CFG_DM_OPENGL;
00495 #endif
00496             continue;
00497         } else if (!strcmp(argv[on_arg], "-pixmap")) {
00498             want_config[CONFIG_DISPLAYMODE] = CFG_DM_PIXMAP;
00499         } else if (!strcmp(argv[on_arg], "-port")) {
00500             if (++on_arg == argc) {
00501                 LOG(LOG_WARNING, "main.c::init_windows",
00502                     "-port requires a port number");
00503                 return 1;
00504             }
00505             want_config[CONFIG_PORT] = atoi(argv[on_arg]);
00506             continue;
00507         } else if (!strcmp(argv[on_arg], "-sdl")) {
00508 #ifndef HAVE_SDL
00509             LOG(LOG_WARNING, "main.c::init_windows",
00510                 "client not compiled with sdl support.  Ignoring -sdl");
00511 #else
00512             want_config[CONFIG_DISPLAYMODE] = CFG_DM_SDL;
00513 #endif
00514             continue;
00515         } else if (!strcmp(argv[on_arg], "-server")) {
00516             if (++on_arg == argc) {
00517                 LOG(LOG_WARNING, "main.c::init_windows",
00518                     "-server requires a host name");
00519                 return 1;
00520             }
00521             server = argv[on_arg];
00522             continue;
00523         } else if (!strcmp(argv[on_arg], "-showicon")) {
00524             want_config[CONFIG_SHOWICON] = TRUE;
00525             continue;
00526         } else if (!strcmp(argv[on_arg], "-smooth")) {
00527             want_config[CONFIG_SMOOTH] = TRUE;
00528         } else if (!strcmp(argv[on_arg], "-nosmooth")) {
00529             want_config[CONFIG_SMOOTH] = FALSE;
00530         } else if (!strcmp(argv[on_arg], "-sound")) {
00531             want_config[CONFIG_SOUND] = TRUE;
00532             continue;
00533         } else if (!strcmp(argv[on_arg], "-nosound")) {
00534             want_config[CONFIG_SOUND] = FALSE;
00535             continue;
00536         } else if (!strcmp(argv[on_arg], "-sound_server")) {
00537             if (++on_arg == argc) {
00538                 LOG(LOG_WARNING, "main.c::init_windows",
00539                     "-sound_server requires an executable pathname");
00540                 return 1;
00541             }
00542             sound_server = argv[on_arg];
00543             continue;
00544         } else if (!strcmp(argv[on_arg], "-split")) {
00545             want_config[CONFIG_SPLITWIN]=TRUE;
00546             continue;
00547         } else if (!strcmp(argv[on_arg], "-nosplit")) {
00548             want_config[CONFIG_SPLITWIN]=FALSE;
00549             continue;
00550         } else if (!strcmp(argv[on_arg], "-resists")) {
00551             if (++on_arg == argc) {
00552                 LOG(LOG_WARNING, "main.c::init_windows",
00553                     "-resists requires a value");
00554                 return 1;
00555             }
00556             want_config[CONFIG_RESISTS]=atoi(argv[on_arg]);
00557             continue;
00558         } else if (!strcmp(argv[on_arg], "-loglevel")) {
00559             extern int MINLOG;
00560 
00561             if (++on_arg == argc) {
00562                 LOG(LOG_WARNING, "main.c::init_windows",
00563                     "-loglevel requires a value");
00564                 return 1;
00565             }
00566             MINLOG = atoi(argv[on_arg]);
00567             continue;
00568         } else if (!strcmp(argv[on_arg], "-splitinfo")) {
00569             want_config[CONFIG_SPLITINFO]=TRUE;
00570             continue;
00571         } else if (!strcmp(argv[on_arg], "-timemapredraw")) {
00572             time_map_redraw=TRUE;
00573             continue;
00574         } else if (!strcmp(argv[on_arg], "-triminfowindow")) {
00575             want_config[CONFIG_TRIMINFO] = TRUE;
00576             continue;
00577         } else if (!strcmp(argv[on_arg], "-notriminfowindow")) {
00578             want_config[CONFIG_TRIMINFO] = FALSE;
00579             continue;
00580         } else if (!strcmp(argv[on_arg], "-updatekeycodes")) {
00581             updatekeycodes=TRUE;
00582             continue;
00583         } else if (!strcmp(argv[on_arg], "-splash")) {
00584             want_config[CONFIG_SPLASH] = TRUE;
00585             continue;
00586         } else if (!strcmp(argv[on_arg], "-nosplash")) {
00587             want_config[CONFIG_SPLASH] = FALSE;
00588             continue;
00589         } else if (!strcmp(argv[on_arg], "-window_xml")) {
00590             if (++on_arg == argc) {
00591                 LOG(LOG_WARNING, "main.c::init_windows",
00592                     "-window_xml requires a glade xml file name");
00593                 return 1;
00594             }
00595             strncpy (window_xml_path, argv[on_arg], MAX_BUF-1);
00596             continue;
00597         } else if (!strcmp(argv[on_arg], "-dialog_xml")) {
00598             if (++on_arg == argc) {
00599                 LOG(LOG_WARNING, "main.c::init_windows",
00600                     "-dialog_xml requires a glade xml file name");
00601                 return 1;
00602             }
00603             strncpy (dialog_xml_path, argv[on_arg], MAX_BUF-1);
00604             continue;
00605         } else {
00606             LOG(LOG_WARNING, "main.c::init_windows",
00607                 "Do not understand option %s", argv[on_arg]);
00608             usage(argv[0]);
00609             return 1;
00610         }
00611     }
00612 
00613     /*
00614      * Move this after the parsing of command line options, since that can
00615      * change the default log level.
00616      */
00617     LOG(LOG_INFO, "Client Version", VERSION_INFO);
00618 
00619     /* Now copy over the values just loaded */
00620     for (on_arg=0; on_arg<CONFIG_NUMS; on_arg++) {
00621         use_config[on_arg] = want_config[on_arg];
00622     }
00623 
00624     image_size = DEFAULT_IMAGE_SIZE * use_config[CONFIG_ICONSCALE] / 100;
00625     map_image_size = DEFAULT_IMAGE_SIZE * use_config[CONFIG_MAPSCALE] / 100;
00626     map_image_half_size = DEFAULT_IMAGE_SIZE * use_config[CONFIG_MAPSCALE] / 200;
00627     if (!use_config[CONFIG_CACHE]) use_config[CONFIG_DOWNLOAD] = FALSE;
00628 
00629     mapdata_init();
00630 
00631     return 0;
00632 }
00633 
00647 void error_dialog(char *description, char *information)
00648 {
00649     GtkWidget *dialog;
00650 
00651     gtk_init(NULL, NULL);
00652     dialog =
00653         gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
00654         GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Crossfire %s\n%s",
00655         VERSION_INFO, description);
00656     gtk_message_dialog_format_secondary_markup(GTK_MESSAGE_DIALOG(dialog),
00657         "%s", information);
00658     gtk_dialog_run(GTK_DIALOG(dialog));
00659     gtk_widget_destroy(dialog);
00660 }
00661 
00674 void my_log_handler(const gchar *log_domain, GLogLevelFlags log_level,
00675                     const gchar *message, gpointer user_data) {
00676     sleep(1);
00677 }
00678 
00685 int
00686 main (int argc, char *argv[])
00687 {
00688     int i, got_one=0;
00689     static char file_cache[ MAX_BUF ];
00690     GdkGeometry geometry;
00691     GladeXML *xml_tree;
00692 
00693 #ifdef ENABLE_NLS
00694     bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
00695     bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
00696     textdomain (GETTEXT_PACKAGE);
00697 #endif
00698 
00699     gtk_set_locale ();
00700     gtk_init (&argc, &argv);
00701 #if 0
00702     g_log_set_handler ("Gtk", G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL
00703                        | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
00704 #endif
00705 
00706     /* parse_args() has to come after init_client_vars() */
00707     init_client_vars();
00708     use_config[CONFIG_MAPWIDTH] = want_config[CONFIG_MAPWIDTH] = 25;
00709     use_config[CONFIG_MAPHEIGHT] = want_config[CONFIG_MAPHEIGHT] = 25;
00710 
00711     wantloginmethod=2;
00712 
00713     parse_args(argc, argv);
00714 
00715     init_theme();
00716 
00717     csocket.inbuf.buf=malloc(MAXSOCKBUF);
00718 
00719 #ifdef WIN32 /* def WIN32 */
00720     maxfd = 0; /* This is ignored on win32 platforms */
00721 
00722     /* This is required for sockets to be used under win32 */
00723     {
00724         WORD Version = 0x0202;
00725         WSADATA wsaData;
00726 
00727         if (WSAStartup( Version, &wsaData ) != 0) {
00728             LOG(LOG_CRITICAL, "main.c::main", "Could not load winsock!");
00729             exit(1);
00730         }
00731     }
00732 #else /* def WIN32 */
00733     signal(SIGPIPE, sigpipe_handler);
00734 #ifdef HAVE_SYSCONF
00735     maxfd = sysconf(_SC_OPEN_MAX);
00736 #else
00737     maxfd = getdtablesize();
00738 #endif
00739 #endif /* def WIN32 */
00740 
00741     if (init_sounds() == -1)
00742         use_config[CONFIG_SOUND] = FALSE;
00743     else use_config[CONFIG_SOUND] = TRUE;
00744 
00745     /*
00746      * Load Glade XML layout files for the main client window and for the other
00747      * popup dialogs.  The popup dialogs must all have the "visible" attribute
00748      * set to "no" so they are not shown initially.
00749      *
00750      * NOTE:  glade_init() is implicitly called on glade_xml_new().
00751      *
00752      * First, load up the common dialogs.  If the XML file path is already set,
00753      * it is because a command-line parameter was used to specify it.  If not
00754      * set, construct the path to the file from the default path and name
00755      * settings.
00756      */
00757     if (! dialog_xml_path[0]) {
00758         strncat(dialog_xml_path, XML_PATH_DEFAULT, MAX_BUF-1);
00759         strncat(dialog_xml_path, dialog_xml_file,
00760             MAX_BUF-strlen(dialog_xml_path)-1);
00761     }
00762     dialog_xml = glade_xml_new(dialog_xml_path, NULL, NULL);
00763     if (! dialog_xml) {
00764         sprintf(dialog_xml_file, "Dialog layout file load failed");
00765         error_dialog(dialog_xml_file, dialog_xml_path);
00766         exit(-1);
00767     }
00768 
00769     /*
00770      * Next, load up the root window.  If the XML file path is already set, it
00771      * is because a command-line parameter was used to specify it.  If not set,
00772      * construct the path to the file from the default settings, and any values
00773      * loaded from the gdefaults2 file.
00774      */
00775     if (! window_xml_path[0]) {
00776         strncat(window_xml_path, XML_PATH_DEFAULT, MAX_BUF-1);
00777         strncat(window_xml_path, window_xml_file,
00778             MAX_BUF-strlen(window_xml_path)-1);
00779     }
00780     window_xml = glade_xml_new(window_xml_path, NULL, NULL);
00781     if (! window_xml) {
00782         sprintf(window_xml_file, "Main window layout file load failed");
00783         error_dialog(window_xml_file, window_xml_path);
00784         exit(-1);
00785     }
00786 
00787     /* Begin connecting signals for the root window loaded by libglade. */
00788     window_root = glade_xml_get_widget(window_xml, "window_root");
00789 
00790     g_signal_connect_swapped ((gpointer) window_root, "key_press_event",
00791         G_CALLBACK (keyfunc), GTK_OBJECT (window_root));
00792     g_signal_connect_swapped ((gpointer) window_root, "key_release_event",
00793         G_CALLBACK (keyrelfunc), GTK_OBJECT (window_root));
00794     g_signal_connect ((gpointer) window_root, "destroy",
00795         G_CALLBACK (on_window_destroy_event), NULL);
00796 
00797     /* Purely arbitrary min window size */
00798     geometry.min_width=640;
00799     geometry.min_height=480;
00800 
00801     gtk_window_set_geometry_hints(GTK_WINDOW(window_root), window_root,
00802                                   &geometry, GDK_HINT_MIN_SIZE);
00803 
00804     /* Set up colors before doing the other initialization functions */
00805     for (i=0; i<NUM_COLORS; i++) {
00806         if ( !gdk_color_parse(colorname[i], &root_color[i])) {
00807             fprintf(stderr, "gdk_color_parse failed (%s)\n",colorname[i]);
00808         }
00809         if ( !gdk_color_alloc (gtk_widget_get_colormap (window_root),
00810                                &root_color[i])) {
00811             fprintf(stderr, "gdk_color_alloc failed\n");
00812         }
00813     }
00814 
00815 
00816     inventory_init(window_root);
00817     info_init(window_root);
00818     keys_init(window_root);
00819     stats_init(window_root);
00820     config_init(window_root);
00821     pickup_init(window_root);
00822     msgctrl_init(window_root);
00823     init_create_character_window();
00824 
00825     load_window_positions(window_root);
00826 
00827     load_theme(TRUE);
00828 
00829     /* We want this as late as possible in the process. This way, adjustments
00830      * that the widgets make on initialization are not visible - this is most
00831      * important with the inventory widget which has to create the panes and
00832      * fill in the data - if the window_root is shown before that, there is a
00833      * brief glimpse of the glade layout, which, IMO, doesn't look great.
00834      * Also, it should be faster to realize this as later as possible. */
00835     gtk_widget_show (window_root);
00836 
00837 
00838     map_init(window_root);
00839 
00840     xml_tree = glade_get_widget_tree(GTK_WIDGET(window_root));
00841     magic_map = glade_xml_get_widget(xml_tree, "drawingarea_magic_map");
00842 
00843     g_signal_connect ((gpointer) magic_map, "expose_event",
00844         G_CALLBACK (on_drawingarea_magic_map_expose_event), NULL);
00845 
00846     snprintf( file_cache, MAX_BUF, "%s/.crossfire/servers.cache", getenv( "HOME" ) );
00847     CONVERT_FILESPEC_TO_OS_FORMAT(file_cache);
00848     cached_server_file = file_cache;
00849 
00850     init_image_cache_data();
00851 
00852 
00853     /* Loop to connect to server/metaserver and play the game */
00854     while (1) {
00855         reset_client_vars();
00856         clear_stat_mapping();
00857         csocket.inbuf.len=0;
00858         csocket.cs_version=0;
00859 
00860         /*
00861          * Perhaps not the best assumption, but we are taking it that if the
00862          * player has not specified a server (ie, server matches compiled in
00863          * default), we use the metaserver.  Otherwise, use the server
00864          * provided, bypassing metaserver.  Also, if the player has already
00865          * played on a server once (defined by got_one), go to the metaserver.
00866          * That gives them the opportunity to quit the client or select another
00867          * server.  We should really add an entry for the last server there
00868          * also.
00869          */
00870         if (!server || got_one) {
00871             draw_splash();
00872             metaserver_get_info(meta_server, meta_port);
00873             get_metaserver();
00874             /* Call this after get_metaserver so one can't do anything
00875              * with the menus at that point.
00876              */
00877             enable_menu_items(TRUE);
00878             negotiate_connection(use_config[CONFIG_SOUND]);
00879         } else {
00880             enable_menu_items(TRUE);
00881             csocket.fd=init_connection(server, use_config[CONFIG_PORT]);
00882             if (csocket.fd == -1) { /* specified server no longer valid */
00883                 server = NULL;
00884                 continue;
00885             }
00886             negotiate_connection(use_config[CONFIG_SOUND]);
00887         }
00888 
00889         got_one=1;
00890 
00891         event_loop();
00892         /*
00893          * if event_loop has exited, we most likely of lost our connection, so
00894          * we loop again to establish a new one.
00895          */
00896 
00897         remove_item_inventory(cpl.ob);
00898         /*
00899          * We know the following is the private map structure in item.c.  But
00900          * we don't have direct access to it, so we still use locate.
00901          */
00902         remove_item_inventory(locate_item(0));
00903         draw_look_list();
00904 
00905         mapdata_reset();
00906         /*
00907          * Need to reset the images so they match up properly and prevent
00908          * memory leaks.
00909          */
00910         reset_image_data();
00911     }
00912     exit(0);    /* never reached */
00913 
00914     return 0;
00915 }
00916 
00928 void get_window_coord(GtkWidget *win,
00929                  int *x,int *y,
00930                  int *wx,int *wy,
00931                  int *w,int *h)
00932 {
00933     /* Position of a window relative to its parent window. */
00934     gdk_window_get_geometry (win->window, x, y, w, h, NULL);
00935     /* Position of the window in root window coordinates. */
00936     gdk_window_get_origin (win->window, wx, wy);
00937     *wx -= *x;
00938     *wy -= *y;
00939 }