diff -r -c freeciv-old/client/civclient.c freeciv/client/civclient.c *** freeciv-old/client/civclient.c Sat Oct 27 01:55:46 2001 --- freeciv/client/civclient.c Mon Dec 24 11:57:01 2001 *************** *** 548,554 **** server_autoconnect(); } } else { ! gui_server_connect(); } } } --- 548,555 ---- server_autoconnect(); } } else { ! popup_main_menu(); ! /* gui_server_connect(); */ } } } diff -r -c freeciv-old/client/gui-gtk/connectdlg.c freeciv/client/gui-gtk/connectdlg.c *** freeciv-old/client/gui-gtk/connectdlg.c Sun Sep 9 01:59:08 2001 --- freeciv/client/gui-gtk/connectdlg.c Mon Dec 24 13:51:01 2001 *************** *** 15,22 **** --- 15,41 ---- #endif #include + #include #include #include + #include + + #include + + #include + + #ifdef HAVE_SYS_TYPES_H + #include + #endif + + /*We really can't work without this. It's absence whould raise an error at configure time*/ + /*#ifdef HAVE_SYS_WAIT_H*/ + #include + /*#endif*/ + + #ifdef HAVE_UNISTD_H + #include + #endif #include *************** *** 33,38 **** --- 52,59 ---- #include "gui_main.h" #include "gui_stuff.h" + #include "inputdlg.h" + #include "connectdlg.h" static GtkWidget *iname, *ihost, *iport; *************** *** 40,45 **** --- 61,78 ---- static GtkWidget *dialog; + static GtkWidget *server_window=NULL; + static GtkWidget *server_output; + static GtkWidget *server_output_scrollbar; + static GtkWidget *server_button_row; + + static GtkWidget *main_menu; + + static int stdin_pipe[2]; + static int stderr_pipe[2]; + static int stdout_pipe[2]; + static pid_t server_pid=-1; + /* meta Server */ static int update_meta_dialog(GtkWidget *meta_list); static void meta_list_callback(GtkWidget *w, gint row, gint column); *************** *** 47,52 **** --- 80,130 ---- static int get_meta_list(GtkWidget *list, char *errbuf, int n_errbuf); + + /************************************************************************** + Tests if the client has started the server. + **************************************************************************/ + int is_server_running() + { + return (server_pid>0); + } + + /************************************************************************** + Kills the server if the client has started it (atexit handler) + **************************************************************************/ + void kill_server() + { + if (is_server_running()) + kill(server_pid,SIGTERM); + } + + /************************************************************************* + Exit without killing the server + *************************************************************************/ + void quit_client_only() + { + server_pid=-1; + exit(0); + } + + /************************************************************************* + + *************************************************************************/ + void show_server_window() + { + gtk_widget_show(server_window); + } + + /************************************************************************* + Updates the button row in the server window + *************************************************************************/ + static void update_server_buttons() + { + if (!server_window) + return; + gtk_widget_set_sensitive(server_button_row,is_server_running()); + } + /************************************************************************** ... **************************************************************************/ *************** *** 120,137 **** return FALSE; } /************************************************************************** ... **************************************************************************/ void gui_server_connect(void) ! { GtkWidget *label, *table, *book, *scrolled, *list, *vbox, *update; static char *titles_[6]= {N_("Server Name"), N_("Port"), N_("Version"), N_("Status"), N_("Players"), N_("Comment")}; static char **titles; char buf [256]; int i; ! if (!titles) titles = intl_slist(6, titles_); gtk_widget_set_sensitive(turn_done_button, FALSE); --- 198,226 ---- return FALSE; } + /************************************************************************** ... **************************************************************************/ + static void join_game_callback(GtkWidget *w,gpointer data) + { + if (w) + destroy_message_dialog(w); + gui_server_connect(); + } + + /************************************************************************* + + *************************************************************************/ void gui_server_connect(void) ! { GtkWidget *label, *table, *book, *scrolled, *list, *vbox, *update; static char *titles_[6]= {N_("Server Name"), N_("Port"), N_("Version"), N_("Status"), N_("Players"), N_("Comment")}; static char **titles; char buf [256]; int i; ! if (!titles) titles = intl_slist(6, titles_); gtk_widget_set_sensitive(turn_done_button, FALSE); *************** *** 365,368 **** --- 454,779 ---- if (try_to_autoconnect()) { gtk_timeout_add(AUTOCONNECT_INTERVAL, try_to_autoconnect, NULL); } + } + + /************************************************************************** + Sends a server command to the stdin pipe + **************************************************************************/ + void send_server_commandline(char *s) + { + write(stdin_pipe[1],s,strlen(s)); + write(stdin_pipe[1],"\n",1); + } + + /************************************************************************* + Callback for buttons in the server window + *************************************************************************/ + static void server_command_button_callback(GtkWidget *w,gpointer data) + { + send_server_commandline((char *)data); + } + + /************************************************************************ + Callback for text entry in the server window + ************************************************************************/ + static void server_command_entry_callback(GtkWidget *w,gpointer data) + { + char *s; + s=gtk_editable_get_chars(GTK_EDITABLE(w),0,-1); + send_server_commandline(s); + g_free(s); + gtk_entry_set_text(GTK_ENTRY(w),""); + } + + /************************************************************************** + Reads input from the server (pipe) + **************************************************************************/ + static void get_pipe_input(gpointer data, + gint fid, + GdkInputCondition condition) + { + char buf[1024]; + int len; + len=read(fid,buf,sizeof(buf)-1); + if (len>0) { + buf[len]=0; + gtk_text_freeze(GTK_TEXT(server_output)); + gtk_text_insert(GTK_TEXT(server_output),NULL,NULL,NULL,buf,-1); + gtk_text_thaw(GTK_TEXT(server_output)); + } + + /* move the scrollbar forward by a ridiculous amount */ + gtk_range_default_vmotion(GTK_RANGE(server_output_scrollbar), 0, 10000); + update_server_buttons(); + } + + /************************************************************************** + SIGCHLD handler + **************************************************************************/ + static RETSIGTYPE server_exit_signal(int signo) + { + const char *message=N_("Server has terminated\n"); + if (is_server_running()) { + if (server_pid==waitpid(server_pid,NULL,WNOHANG)) { + server_pid=-1; + /* Notify the gui to disable buttons + Calling update_server_buttons() here leads to X11 + networking problems like this: + Xlib: unexpected async reply (sequence 0x1499f)! + */ + write(stdout_pipe[1],_(message),strlen(_(message))); + + } + } + } + + /************************************************************************** + Creates the server window (which shows stdout and stderr of the server) + **************************************************************************/ + static void create_server_window() + { + GtkWidget *entry; + GtkWidget *button; + GtkWidget *vbox; + GtkWidget *hbox; + char title[25]; + sprintf(title, _("Game Control -- Port %d"),server_port); + server_window=gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(server_window),title); + gtk_signal_connect(GTK_OBJECT(server_window),"delete_event", + GTK_SIGNAL_FUNC(gtk_widget_hide),server_window); + vbox=gtk_vbox_new(FALSE,5); + gtk_container_add(GTK_CONTAINER(server_window),vbox); + server_output=gtk_text_new(NULL,NULL); + gtk_text_set_editable(GTK_TEXT(server_output),FALSE); + server_output_scrollbar=gtk_vscrollbar_new(GTK_TEXT(server_output)->vadj); + hbox=gtk_hbox_new(FALSE,0); + gtk_box_pack_start(GTK_BOX(hbox),server_output,TRUE,TRUE,0); + gtk_box_pack_start(GTK_BOX(hbox),server_output_scrollbar,FALSE,FALSE,0); + gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,0); + gtk_widget_set_usize(server_output,600,100); + + hbox=gtk_hbox_new(FALSE,5); + gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,0); + + button=gtk_button_new_with_label(_("Start game")); + gtk_box_pack_start(GTK_BOX(hbox),button,FALSE,FALSE,0); + gtk_signal_connect(GTK_OBJECT(button),"clicked", + GTK_SIGNAL_FUNC(server_command_button_callback),"start"); + + button=gtk_button_new_with_label(_("End game")); + gtk_signal_connect(GTK_OBJECT(button),"clicked", + GTK_SIGNAL_FUNC(server_command_button_callback),"quit"); + gtk_box_pack_start(GTK_BOX(hbox),button,FALSE,FALSE,0); + + entry=gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(hbox),entry,TRUE,TRUE,0); + gtk_signal_connect(GTK_OBJECT(entry),"activate", + GTK_SIGNAL_FUNC(server_command_entry_callback), + NULL); + server_button_row=hbox; + gtk_widget_show_all(vbox); + + if (pipe(stdin_pipe)) { + freelog(LOG_FATAL,_("Cannot create pipe")); + exit(1); + } + if (pipe(stdout_pipe)) { + freelog(LOG_FATAL,_("Cannot create pipe")); + exit(1); + } + if (pipe(stderr_pipe)) { + freelog(LOG_FATAL,_("Cannot create pipe")); + exit(1); + } + gdk_input_add(stdout_pipe[0],GDK_INPUT_READ, + get_pipe_input,NULL); + gdk_input_add(stderr_pipe[0],GDK_INPUT_READ, + get_pipe_input,NULL); + atexit(kill_server); + signal(SIGCHLD,server_exit_signal); + update_server_buttons(); + } + + + /************************************************************************* + Starts the server. + *************************************************************************/ + static void start_server(char **argv) + { + if (!server_window) /* will also create pipes */ + create_server_window(); + server_pid=fork(); + if (server_pid==0) { + + /* redirecting stdio */ + dup2(stdout_pipe[1],1); + dup2(stderr_pipe[1],2); + dup2(stdin_pipe[0],0); + + execvp("./ser",argv); + execvp("./server/civserver",argv); + execvp("civserver",argv); + /* This line is only reached if civserver cannot be started. + Calling exit here is dangerous due to X11 problems + (async replies) */ + _exit(1); + } + update_server_buttons(); + gtk_widget_show(server_window); + server_autoconnect(); + } + + /************************************************************************** + Finds the lowest port which can be used for the server (starting at the default 5555) + **************************************************************************/ + int min_free_port() + { + int port, n, s; + struct sockaddr_in tmp; + s=socket(AF_INET, SOCK_STREAM, 0); + n=INADDR_ANY; + port=5554; /* make looping convinient */ + do{ + port++; + fprintf(stderr,"Trying %d...\n",port); + memset(&tmp,0,sizeof(struct sockaddr_in)); + tmp.sin_family=AF_INET; + tmp.sin_port=htons(port); + memcpy(&tmp.sin_addr, &n, sizeof(long)); + }while( bind(s,(struct sockaddr*) &tmp, sizeof(struct sockaddr_in)) ); + close(s); + fprintf(stderr,"Returning %d\n",port); + return(port); + } + + /************************************************************************** + Starts the server without arguments. + **************************************************************************/ + void start_server_for_new_game() + { + char *argv[4]; + argv[0]="civserver"; + argv[1]="-p"; + argv[2]=malloc(6*sizeof(char)); /* This is a memory leak, but it's small, and one time, and + I'm not sure when it would be safe to free() */ + /*" "; easy way to put it on the stack*/ + sprintf(argv[2],"%d",server_port); + argv[3]=NULL; + start_server(argv); + } + + /************************************************************************* + Starts the server with -f option to load a game + *************************************************************************/ + void start_server_load_game(char *filename) + { + char *argv[5]; + argv[0]="civserver"; + argv[1]="-f"; + argv[2]=filename; + argv[3]="-p"; + argv[4]=" "; /*easy way to put it on the stack*/ + sprintf(argv[4],"%d",server_port); + argv[5]=NULL; + start_server(argv); + } + + /************************************************************************** + + **************************************************************************/ + static void filesel_callback(GtkWidget *w,gpointer data) + { + char *filename; + filename=gtk_file_selection_get_filename(GTK_FILE_SELECTION(data)); + gtk_widget_destroy(main_menu); + gtk_widget_set_sensitive(top_vbox,TRUE); + server_port=min_free_port(); + start_server_load_game(filename); + } + + + /************************************************************************** + + **************************************************************************/ + static void load_game_name_ok_callback(GtkWidget *w,gpointer data) + { + GtkWidget *filesel; + sz_strlcpy(player_name,input_dialog_get_input(w)); + input_dialog_destroy(w); + + filesel=gtk_file_selection_new(_("Please select a game file to load")); + gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button), + "clicked",GTK_SIGNAL_FUNC(filesel_callback),filesel); + gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(filesel) + ->ok_button),"clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + (gpointer)filesel); + gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(filesel) + ->cancel_button),"clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + (gpointer)filesel); + gtk_widget_show(filesel); + } + + /************************************************************************** + Callback for the new game button + **************************************************************************/ + static void new_game_name_ok_callback(GtkWidget *w,gpointer data) + { + sz_strlcpy(player_name,input_dialog_get_input(w)); + input_dialog_destroy(w); + gtk_widget_destroy(main_menu); + server_port=min_free_port(); + start_server_for_new_game(); + } + + /************************************************************************** + + **************************************************************************/ + static void name_input_destroy_callback(GtkWidget *w, gpointer data) + { + input_dialog_destroy(w); + } + + /************************************************************************** + + **************************************************************************/ + static void new_game_callback(GtkWidget *w,gpointer data) + { + input_dialog_create(top_vbox, + _("New Game"),_("Enter your name:"),player_name, + new_game_name_ok_callback,NULL, + name_input_destroy_callback,NULL); + } + + /************************************************************************** + + **************************************************************************/ + static void load_game_callback(GtkWidget *w,gpointer data) + { + input_dialog_create(top_vbox, + _("Load Game"),_("Enter your name:"),player_name, + load_game_name_ok_callback,NULL, + name_input_destroy_callback,NULL); + } + + /************************************************************************** + + **************************************************************************/ + void popup_main_menu() + { + if (server_window) + gtk_widget_hide(server_window); + main_menu=popup_message_dialog(top_vbox, + _("Start a game"), + _("What do you wish to to?"), + _("New Game"),new_game_callback,NULL, + _("Load Game"),load_game_callback,NULL, + _("Join Game"),join_game_callback,NULL, + _("Quit Game"),gtk_main_quit,NULL, + NULL); + gtk_widget_set_sensitive(top_vbox,FALSE); + gtk_signal_connect(GTK_OBJECT(main_menu),"delete_event", + GTK_SIGNAL_FUNC(gtk_main_quit), NULL); } diff -r -c freeciv-old/client/gui-gtk/menu.c freeciv/client/gui-gtk/menu.c *** freeciv-old/client/gui-gtk/menu.c Sat Oct 27 01:55:54 2001 --- freeciv/client/gui-gtk/menu.c Mon Dec 24 11:57:19 2001 *************** *** 32,37 **** --- 32,38 ---- #include "cityrep.h" #include "civclient.h" #include "clinet.h" + #include "connectdlg.h" #include "control.h" #include "dialogs.h" #include "finddlg.h" *************** *** 68,76 **** --- 69,79 ---- MENU_GAME_SAVE_SETTINGS, MENU_GAME_SERVER_OPTIONS1, MENU_GAME_SERVER_OPTIONS2, + MENU_GAME_SERVER_WINDOW, MENU_GAME_OUTPUT_LOG, MENU_GAME_CLEAR_OUTPUT, MENU_GAME_DISCONNECT, + MENU_GAME_QUIT_CLIENT, MENU_GAME_QUIT, MENU_KINGDOM_TAX_RATE, *************** *** 175,180 **** --- 178,186 ---- case MENU_GAME_SERVER_OPTIONS2: send_report_request(REPORT_SERVER_OPTIONS2); break; + case MENU_GAME_SERVER_WINDOW: + show_server_window(); + break; case MENU_GAME_OUTPUT_LOG: log_output_window(); break; *************** *** 184,189 **** --- 190,198 ---- case MENU_GAME_DISCONNECT: disconnect_from_server(); break; + case MENU_GAME_QUIT_CLIENT: + quit_client_only(); + break; case MENU_GAME_QUIT: exit(0); break; *************** *** 558,563 **** --- 567,574 ---- game_menu_callback, MENU_GAME_SERVER_OPTIONS1 }, { "/" N_("Game") "/" N_("Server Opt _ongoing"), NULL, game_menu_callback, MENU_GAME_SERVER_OPTIONS2 }, + { "/" N_("Game") "/" N_("Game Control (Server)"), NULL, + game_menu_callback, MENU_GAME_SERVER_WINDOW, }, { "/" N_("Game") "/sep3", NULL, NULL, 0, "" }, { "/" N_("Game") "/" N_("_Export Log"), NULL, *************** *** 567,573 **** { "/" N_("Game") "/sep4", NULL, NULL, 0, "" }, { "/" N_("Game") "/" N_("_Disconnect"), NULL, ! game_menu_callback, MENU_GAME_DISCONNECT }, { "/" N_("Game") "/" N_("_Quit"), "q", gtk_main_quit, 0 }, /* Kingdom menu ... */ --- 578,586 ---- { "/" N_("Game") "/sep4", NULL, NULL, 0, "" }, { "/" N_("Game") "/" N_("_Disconnect"), NULL, ! game_menu_callback, MENU_GAME_DISCONNECT }, ! { "/" N_("Game") "/" N_("Quit client only"), NULL, ! game_menu_callback, MENU_GAME_QUIT_CLIENT }, { "/" N_("Game") "/" N_("_Quit"), "q", gtk_main_quit, 0 }, /* Kingdom menu ... */ *************** *** 955,960 **** --- 968,976 ---- *****************************************************************/ void update_menus(void) { + menus_set_sensitive("
/_Game/Quit client only", is_server_running()); + menus_set_sensitive("
/_Game/Game Control (Server)", is_server_running()); + menus_set_sensitive("
/_Game/_Disconnect",!is_server_running()); if(get_client_state()!=CLIENT_GAME_RUNNING_STATE) { menus_set_sensitive("
/_Reports", FALSE); menus_set_sensitive("
/_Kingdom", FALSE); diff -r -c freeciv-old/client/include/connectdlg_g.h freeciv/client/include/connectdlg_g.h *** freeciv-old/client/include/connectdlg_g.h Wed Aug 29 07:58:34 2001 --- freeciv/client/include/connectdlg_g.h Mon Dec 24 11:57:25 2001 *************** *** 15,19 **** --- 15,28 ---- void gui_server_connect(void); void server_autoconnect(void); + int is_server_running(void); + void kill_server(void); + void quit_client_only(void); + void show_server_window(void); + void send_server_commandline(char *s); + void start_server_for_new_game(void); + void start_server_load_game(char *filename); + void popup_main_menu(void); + #endif /* FC__CONNECTDLG_G_H */