/*--------------------------------------------------------------------------*/ /* main */ /*--------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gtk-callbacks.h" #include "gtk-interface.h" #include "gtk-support.h" #include "main.h" #include "canvas.h" #include "theme.h" #include "board.h" #include "iface.h" #include "audio.h" #include "field.h" #include "main-random.h" /*--------------------------------------------------------------------------*/ /* defines */ /*--------------------------------------------------------------------------*/ #define APP_NAME "xarchon" #define UPF (1000000 / FPS) /* usecs per frame */ #define TIMER_RES 10000 /* OS timer resolution */ #define UPF_MIN (UPF - UPF % TIMER_RES) #define UPF_MAX (UPF + UPF % TIMER_RES) /*--------------------------------------------------------------------------*/ /* functions */ /*--------------------------------------------------------------------------*/ static void set_sensitive_options(int game_active); static void set_visible_gui(int visible); static void progress_func(char *msg, float progress); static void init_gui(int *argc, char *argv[]); static void init(int *argc, char *argv[]); static void play(int n); static void loop(void); /*--------------------------------------------------------------------------*/ /* variables */ /*--------------------------------------------------------------------------*/ int random_index; static GtkWidget *window, *menubar, *progressbar; static Atom wm_protocols, wm_delete_window; static int initializing = 1; static int quitting = 0; /*--------------------------------------------------------------------------*/ /* main_random */ /*--------------------------------------------------------------------------*/ int main_random(void) { int v; v = random_numbers[random_index % RANDOM_COUNT]; random_index++; return v; } /*--------------------------------------------------------------------------*/ /* main_msgbox */ /*--------------------------------------------------------------------------*/ void main_msgbox(char *msg) { GtkWidget *dialog, *label, *okay_button; dialog = gtk_dialog_new(); label = gtk_label_new(msg); okay_button = gtk_button_new_with_label("OK"); gtk_signal_connect_object(GTK_OBJECT(okay_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(dialog)); gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), okay_button); gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); gtk_window_set_modal(GTK_WINDOW(dialog), 1); gtk_widget_show_all(dialog); } /*--------------------------------------------------------------------------*/ /* set_sensitive_options */ /*--------------------------------------------------------------------------*/ static void set_sensitive_options(int game_active) { gtk_widget_set_sensitive(lookup_widget(window, "mnu_game_new"), !game_active); gtk_widget_set_sensitive(lookup_widget(window, "mnu_game_stop"), game_active); gtk_widget_set_sensitive(lookup_widget(window, "mnu_settings_define"), !game_active); gtk_widget_set_sensitive(lookup_widget(window, "mnu_settings_select"), !game_active); gtk_widget_set_sensitive(lookup_widget(window, "mnu_settings_theme"), !game_active); } /*--------------------------------------------------------------------------*/ /* set_visible_gui */ /*--------------------------------------------------------------------------*/ static void set_visible_gui(int visible) { if (visible) { gtk_widget_show(menubar); gtk_widget_show(lookup_widget(window, "logo")); gtk_widget_show(progressbar); } else { gtk_widget_hide(menubar); gtk_widget_hide(lookup_widget(window, "logo")); gtk_widget_hide(progressbar); } gdk_flush(); } /*--------------------------------------------------------------------------*/ /* main_game_new */ /*--------------------------------------------------------------------------*/ void main_game_new(GtkMenuItem *menuitem, gpointer user_data) { char *msg; int light_first; set_visible_gui(0); msg = iface_start(&light_first); quitting = 0; /* this is important */ if (msg != NULL) { set_visible_gui(1); progress_func(msg, 1.0); return; } set_sensitive_options(1); board_start_game(light_first); if (menuitem != NULL) /* NULL when called by main() */ gtk_main_quit(); } /*--------------------------------------------------------------------------*/ /* main_game_unpause */ /*--------------------------------------------------------------------------*/ void main_game_unpause(GtkMenuItem *menuitem, gpointer user_data) { if (board_pause_game(0)) gtk_main_quit(); } /*--------------------------------------------------------------------------*/ /* main_game_stop */ /*--------------------------------------------------------------------------*/ void main_game_stop(GtkMenuItem *menuitem, gpointer user_data) { board_end_game(); set_sensitive_options(0); progress_func("Game Ended", 1.0); } /*--------------------------------------------------------------------------*/ /* main_toggle_sound */ /*--------------------------------------------------------------------------*/ void main_toggle_sound(GtkMenuItem *menuitem, gpointer user_data) { if (audio_isenabled()) audio_disable(); else audio_enable(); } /*--------------------------------------------------------------------------*/ /* main_game_exit */ /*--------------------------------------------------------------------------*/ void main_game_exit(GtkMenuItem *menuitem, gpointer user_data) { quitting = 1; gtk_main_quit(); } /*--------------------------------------------------------------------------*/ /* main_help_tips */ /*--------------------------------------------------------------------------*/ void main_help_tips(GtkMenuItem *menuitem, gpointer user_data) { static GtkWidget *window = NULL; static int destroying = 0; if (window == NULL) { window = create_tips_window(); gtk_widget_show(window); } else if (!destroying) { destroying = 1; gtk_widget_destroy(window); window = NULL; destroying = 0; } } /*--------------------------------------------------------------------------*/ /* main_help_about */ /*--------------------------------------------------------------------------*/ void main_help_about(GtkMenuItem *menuitem, gpointer user_data) { static GtkWidget *window = NULL; static int destroying = 0; if (window == NULL) { window = create_about_window(); gtk_widget_show(window); } else if (!destroying) { destroying = 1; gtk_widget_destroy(window); window = NULL; destroying = 0; } } /*--------------------------------------------------------------------------*/ /* main_window_expose_event */ /*--------------------------------------------------------------------------*/ gboolean main_window_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { /* redraw canvas only if a game is in progress */ if (gtk_main_level() == 0 && board_pause_game(-1)) canvas_refresh_all(); return TRUE; } /*--------------------------------------------------------------------------*/ /* main_window_destroy_event */ /*--------------------------------------------------------------------------*/ void main_window_destroy_event(GtkObject *object, gpointer data) { if (initializing) exit(EXIT_SUCCESS); quitting = 1; gtk_main_quit(); } /*--------------------------------------------------------------------------*/ /* progress_func */ /*--------------------------------------------------------------------------*/ void progress_func(char *msg, float progress) { if (progress == 0.0) gtk_widget_set_sensitive(menubar, FALSE); if (progress == 1.0) gtk_widget_set_sensitive(menubar, TRUE); gtk_progress_set_format_string(GTK_PROGRESS(progressbar), msg); gtk_progress_bar_update(GTK_PROGRESS_BAR(progressbar), progress); if (gtk_main_level() == 0) { while (gtk_events_pending()) gtk_main_iteration(); gdk_flush(); } } /*--------------------------------------------------------------------------*/ /* init_gui */ /*--------------------------------------------------------------------------*/ void init_gui(int *argc, char *argv[]) { GtkPixmap *pixmap; gtk_init(argc, &argv); wm_protocols = XInternAtom(GDK_DISPLAY(), "WM_PROTOCOLS", False); wm_delete_window = XInternAtom(GDK_DISPLAY(), "WM_DELETE_WINDOW", False); add_pixmap_directory(DATADIR); /* a glade thingy */ window = create_main_window(); gtk_widget_set_usize(window, CANVAS_WIDTH, CANVAS_HEIGHT); gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(gtk_false), NULL); menubar = lookup_widget(window, "menubar"); progressbar = lookup_widget(window, "progressbar"); set_sensitive_options(0); gtk_widget_set_sensitive(menubar, FALSE); gtk_widget_show(window); XSelectInput(GDK_DISPLAY(), GDK_WINDOW_XWINDOW(window->window), KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | ExposureMask | FocusChangeMask); pixmap = GTK_PIXMAP(create_pixmap(window, "icon.xpm")); gdk_window_set_icon(window->window, NULL, pixmap->pixmap, pixmap->mask); gtk_widget_destroy(GTK_WIDGET(pixmap)); } /*--------------------------------------------------------------------------*/ /* init */ /*--------------------------------------------------------------------------*/ void init(int *argc, char *argv[]) { char str[64]; iface_config_read(); init_gui(argc, argv); canvas_init(GDK_DISPLAY(), GDK_WINDOW_XWINDOW(window->window), CANVAS_WIDTH, CANVAS_HEIGHT); canvas_install_colormap(0); audio_init(); theme_init(progress_func); srandom(time(NULL)); random_index = random() % RANDOM_COUNT; initializing = 0; sprintf(str, "Welcome to X ARCHON, version %s", VERSION); progress_func(str, 1.0); } /*--------------------------------------------------------------------------*/ /* display_event */ /*--------------------------------------------------------------------------*/ #if DEBUG static void display_event(XEvent *ev) { static char *Event_Names[LASTEvent] = { NULL, /* 0 */ NULL, "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease", "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut", "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityExpose", NULL, /* 16 */ NULL, "UnmapNotify", "MapNotify", "MapRequest", NULL, /* 21 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "ClientMessage", "MappingNotify" }; printf("Event %s (%d) Received\n", Event_Names[ev->type], ev->type); } #endif /*--------------------------------------------------------------------------*/ /* main_handle_events */ /*--------------------------------------------------------------------------*/ int main_handle_events(int in_board_game) { XEvent ev; int key; while (XEventsQueued(GDK_DISPLAY(), QueuedAfterReading) > 0) { XNextEvent(GDK_DISPLAY(), &ev); #ifdef DEBUG display_event(&ev); #endif switch (ev.type) { case KeyPress: if (in_board_game) { key = XLookupKeysym((XKeyEvent *)&ev, 0); /* if Escape on game that has ended, or if F12 */ if ((key == XK_Escape && !board_pause_game(-1)) || key == XK_F12) { main_game_stop(NULL, NULL); return 0; } /* if Escape on a non-network game */ if (key == XK_Escape && iface_is_pausable()) { board_pause_game(1); progress_func("Game Paused", 1.0); return 0; } /* if F11 */ if (key == XK_F11) main_toggle_sound(NULL, NULL); } /* fallthrough */ case KeyRelease: canvas_key_event((XKeyEvent *)&ev); break; case MotionNotify: case ButtonPress: case ButtonRelease: canvas_mouse_event(&ev); break; case Expose: if (ev.xexpose.count == 0) canvas_refresh_all(); break; case MappingNotify: XRefreshKeyboardMapping(&ev.xmapping); break; case FocusIn: case FocusOut: if (in_board_game && iface_is_pausable()) board_pause_game(ev.type == FocusOut); break; case ClientMessage: if (ev.xclient.message_type == wm_protocols && ev.xclient.data.l[0] == wm_delete_window) { quitting = 1; return 0; } } } return 1; } /*--------------------------------------------------------------------------*/ /* play */ /*--------------------------------------------------------------------------*/ void play(int n) { struct itimerval itv; signal(SIGALRM, play); /* always re-install signal handler */ if (n != 0) /* if acting as signal handler */ return; itv.it_interval.tv_sec = itv.it_value.tv_sec = 0; while (1) { /* timing logic: at 40 fps, we need to get control every 25000us, */ /* but the Linux timer ticks at 10ms == 10000us. Control would be */ /* returned only after 30000us, which is like working at 33 fps. */ /* Workaround: alternate the pause between 20000 and 30000 usec, */ /* keeping an average of 25000us per frame, which is 40 fps. */ if (itv.it_interval.tv_usec == UPF_MIN) itv.it_interval.tv_usec = itv.it_value.tv_usec = UPF_MAX; else itv.it_interval.tv_usec = itv.it_value.tv_usec = UPF_MIN; setitimer(ITIMER_REAL, &itv, NULL); pause(); signal(SIGALRM, play); /* re-install signal handler */ if (!main_handle_events(1)) return; board_frame(); } } /*--------------------------------------------------------------------------*/ /* loop */ /*--------------------------------------------------------------------------*/ void loop(void) { while (1) { gtk_main(); if (quitting) return; set_visible_gui(0); canvas_install_colormap(1); canvas_refresh_all(); canvas_mouse_cursor(1); play(0); canvas_mouse_cursor(0); if (quitting) return; canvas_install_colormap(0); set_visible_gui(1); } } /*--------------------------------------------------------------------------*/ /* main */ /*--------------------------------------------------------------------------*/ #ifndef GENETICS_MAIN int main(int argc, char *argv[]) { init(&argc, argv); #ifndef AUTOPILOT loop(); #else { int game_num = 1, i; int lgt, drk; int lgt_x, lgt_y; int drk_x, drk_y; CELL *cell; ACTOR *winner; if (0) loop(); printf("main: running an autopilot game.\n"); canvas_enable(0); audio_enable(0); iface_start(&lgt); for (i = 0; i < 20; i++) for (lgt = ACTOR_LIGHT_FIRST; lgt <= ACTOR_LIGHT_LAST; lgt++) for (drk = ACTOR_DARK_FIRST; drk <= ACTOR_DARK_LAST; drk++) { board_start_game(lgt); printf("* * * * * actor %d battles %d * * * * * (%d)\n", lgt, drk, i); fprintf(stderr, "* * * * * actor %d battles %d * * * * * (%d)\n", lgt, drk, i); board_find_actor(lgt, &lgt_x, &lgt_y); board_find_actor(drk, &drk_x, &drk_y); cell = &board_cells[drk_y][drk_x]; cell->flags &= ~CELL_LUMI_MASK; cell->flags |= CELL_LIGHT; field_start_game(board_cells[lgt_y][lgt_x].actor, board_cells[drk_y][drk_x].actor, cell, 0, 0); do winner = field_frame(); while (winner == NULL); /* board_end_game(); */ } iface_config_write(); printf("All Done\n"); } #endif return 0; } #endif /* GENETICS_MAIN */