


/*
 * GtkScare is a runner for Adrift text adventure games.
 * This program is released under GNU GPL. See the file COPYING.TXT for
 * details.
 * Copyright (c) 2004 Pallav Nawani
 *
 */




#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <ctype.h>

#include "gtk/gtk.h"
#include "gdk/gdkkeysyms.h"

#include "callbacks.h"
#include "interface.h"
#include "support.h"
#include "gtkscare.h"
#include "config.h"


extern char fstring[256];

void
on_main_win_destroy_event              (GtkObject       *object,
                                        gpointer         user_data)
{

}





/*
 * 
 * This callback is activated when Enter key is pressed in the
 * gtkentry widget.
 *
 *
 */
void on_textentry(GtkObject *entry, gpointer user_data)
{
   GtkEntry *gentry;
   Gtk_sdata *sdata;
   GtkTextBuffer *tbuf;
   GtkTextIter giter;
   char *instext;

   gentry = GTK_ENTRY(entry);
   sdata = (Gtk_sdata *)user_data;
   sdata->got_input = 1;
   strcpy(sdata->userin, gtk_entry_get_text(gentry));

   instext = (char *)malloc(strlen(sdata->userin)+2);
   if(NULL == instext)
      return;

   sprintf(instext, "%s\n", sdata->userin);
   tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(sdata->textw));
   gtk_text_buffer_get_end_iter(tbuf, &giter);
   gtk_text_buffer_insert_with_tags_by_name(tbuf,
	 &giter, instext, -1, "userinput", NULL);

   gtk_text_buffer_get_end_iter(tbuf, &giter);
   gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(sdata->textw),
	 gtk_text_buffer_get_insert(tbuf),
	 0.2, 1, 0, 0.5);

   // Store the previous commands
   if(instext[0] != '\n') {
      sdata->spoint = sdata->ipoint;
      strcpy(sdata->cmds[sdata->ipoint++], sdata->userin);
      sdata->num_cmds++;
      if(sdata->ipoint >= CMDBUF-1)
	 sdata->ipoint = 0;
   }

   gtk_entry_set_text(gentry, "");

   // Log input
   if(sdata->log != NULL)
      fprintf(sdata->log, "%s\n", sdata->userin);


   free(instext);

}




/*
 * 
 * This callback is called when the menu item open game is
 * activated
 *
 *
 */
void on_open_game_activate (GtkMenuItem *menuitem,
      gpointer user_data)
{
   Gtk_sdata *sdata;
   GtkWidget *fsel;
   GtkTextBuffer *tbuf;
   GtkTextTagTable *ttable;
   GtkTextIter giter;

   PangoFontDescription *pdes;
   
   char title[512];
   char *cptr;
   
   sdata = (Gtk_sdata *)user_data;
   
   sdata->yesno   = DNORESPONSE;
   sdata->menu    = 1;
   sdata->command = OPEN_GAME;

   fsel  = create_fileselection (sdata, 0);
   gtk_file_selection_set_filename(GTK_FILE_SELECTION(fsel),
	 sdata->name);
   gtk_widget_show(fsel);

   while(sdata->yesno == DNORESPONSE)
   {
      gtk_main_iteration_do(1);
   }

   if(sdata->yesno == DNO)
      return;

   strcpy(title, "GtkScare: ");
   strcat(title, sc_get_game_name(sdata->sgame));
   strcat(title, " by ");
   strcat(title, sc_get_game_author(sdata->sgame));

   gtk_window_set_title(GTK_WINDOW(sdata->mwin), title);
   gtk_entry_set_text(GTK_ENTRY(sdata->entry), "");

   /* Attempt to set default game font */
   cptr = sc_get_game_preferred_font (sdata->sgame);
   if(NULL != cptr)
   {
      pdes = pango_font_description_from_string(cptr);
      gtk_widget_modify_font(sdata->textw, pdes);
      pango_font_description_free(pdes);
   }

   /* disable score change notification by default */
   sc_set_game_notify_score_change(sdata->sgame, FALSE);
   sc_set_game_verbose(sdata->sgame, sdata->verbose);

   sc_interpret_game(sdata->sgame);
   
   /* reset tag stack */
   sdata->tsize = 1;

   /* Reset font stack */
   if(sdata->ftag != NULL) {
      tbuf   = gtk_text_view_get_buffer(GTK_TEXT_VIEW(sdata->textw));
      ttable = gtk_text_buffer_get_tag_table(tbuf);
      gtk_text_tag_table_remove(ttable, sdata->ftag);
      sdata->ftag = NULL;
   }
   sdata->ftop = 0;


   /* Reset statusbar */
   if(sdata->got_yesno)
      gtk_statusbar_pop(GTK_STATUSBAR(sdata->sbar),
	    sdata->got_yesno);
   sdata->got_yesno = 0;

   /* Reset game name */
   sdata->gname[0]	= '\0';
   
   /* If the game has been won/lost tell the user about it */
   if(sc_has_game_completed (sdata->sgame))
   {
      tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(sdata->textw));
      gtk_text_buffer_get_end_iter(tbuf, &giter);

      gtk_text_buffer_insert_with_tags_by_name(tbuf,
	    &giter, "\nTHE GAME HAS ENDED\n\n", -1,
	    "center", "importantinfo", "bold", NULL);

      gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(sdata->textw),
	    gtk_text_buffer_get_insert(tbuf),
	    0.2, 1, 0, 0.5);

   }

   /* cleanup */
   sc_free_game (sdata->sgame);
   sdata->sgame = NULL;


}




/*
 *
 * 
 * This callback is activated when the user selects
 * restart game from the gtkscare menu
 *
 *
 */
void on_restart_game_activate (GtkMenuItem *menuitem,
      gpointer user_data)
{
   GtkWidget *confirm;
   Gtk_sdata *sdata;
   
   sdata   = (Gtk_sdata *)user_data;
   if(sdata->sgame == NULL)
      return;

   sdata->yesno   = DNORESPONSE;
   sdata->command = RESTART_GAME;
   confirm = create_confirmation_dlg(sdata,
	 "Really restart the game?");

   gtk_widget_show(confirm);
   while(sdata->yesno == DNORESPONSE)
   {
      gtk_main_iteration_do(1);
   }

   if(sdata->yesno == DNO)
      return;

   if(sc_is_game_running (sdata->sgame)) 
      sc_restart_game(sdata->sgame);

}




/*
 *
 * 
 * This callback is activated when the user choses restore game
 * from the gtkscare menu
 *
 *
 */
void on_restore_game_activate (GtkMenuItem *menuitem,
      gpointer user_data)
{
   Gtk_sdata *sdata;
   
   sdata = (Gtk_sdata *)user_data;
   if(sdata->sgame == NULL)
      return;

   sdata->command = LOAD_SAVEFILE;
   if(NULL != sdata->sgame
	 && sc_is_game_running (sdata->sgame))
      sc_load_game(sdata->sgame);

}





/*
 *
 * This callback is called when the user chooses 'save game as..'
 * from the menu
 *
 * 
 */
void on_save_game_as_activate (GtkMenuItem *menuitem,
      gpointer user_data)
{
   Gtk_sdata *sdata;

   sdata = (Gtk_sdata *)user_data;
   sdata->menu = 1;
   sdata->command = SAVE_GAME;

   if(sdata->sgame == NULL)
      return;

   if(sc_is_game_running (sdata->sgame)) 
      sc_save_game (sdata->sgame);
}



/*
 *
 * This callback is used to save a currently running game
 *
 */
void on_quit_game_activate (GtkMenuItem  *menuitem,
      gpointer user_data)
{
   Gtk_sdata *sdata;
   GtkWidget *confirm;
   GtkTextBuffer *tbuf;
   GtkTextIter giter;

   sdata = (Gtk_sdata *)user_data;
   sdata->menu = 1;

   if(sdata->sgame == NULL)
      return;

   sdata->yesno = DNORESPONSE;
   confirm = create_confirmation_dlg(sdata,
	 "Are you sure you want to quit the current game?");

   gtk_widget_show(confirm);
   while(sdata->yesno == DNORESPONSE)
   {
      gtk_main_iteration_do(1);
   }

   if(sdata->yesno == DNO)
      return;
   
   tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(sdata->textw));
   gtk_text_buffer_get_end_iter(tbuf, &giter);

   gtk_text_buffer_insert_with_tags_by_name(tbuf,
	 &giter, "\nGAME ABORTED (YOU COULD NOW START A NEW GAME)\n\n", -1,
	 "center", "importantinfo", "bold", NULL);

   gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(sdata->textw),
	 gtk_text_buffer_get_insert(tbuf),
	 0.2, 1, 0, 0.5);


   gtk_window_set_title(GTK_WINDOW(sdata->mwin), "GtkScare");
   if(sc_is_game_running (sdata->sgame)) 
      sc_quit_game (sdata->sgame);
}


/*
 *
 * 
 * This callback is called when you choose the exit option
 * from the menu.
 *
 *
 */
void on_exit_activate (GtkMenuItem *menuitem,
      gpointer user_data)
{
   GtkWidget *confirm;
   Gtk_sdata *sdata;
   
   sdata   = (Gtk_sdata *)user_data;
   sdata->yesno = DNORESPONSE;
   confirm = create_confirmation_dlg(sdata,
	 "Are you sure you want to exit?");

   gtk_widget_show(confirm);
   while(sdata->yesno == DNORESPONSE)
   {
      gtk_main_iteration_do(1);
   }

   if(sdata->yesno == DNO)
      return;

   write_config();

   /*
    * Just crash out. There is no other option. If I try to cleanup
    * with gtk_main_quit(), there is a problem when the game is
    * still running. In that case, gtk windows are destroyed, but
    * the app dosen't exit. Instead, if I try quitting the game
    * first, a setjmp occurs and control leaves this function!
    *
    */
   exit(0);

}




/*
 *
 * This callback is activated when the user chooses the
 * option 'set display font color' from the pulldown menu
 *
 */
void on_set_display_font_color_activate (GtkMenuItem *menuitem,
      gpointer user_data)
{

   GtkColorSelectionDialog *colorsel;
   Gtk_sdata *sdata;
   
   sdata   = (Gtk_sdata *)user_data;
   sdata->command = SET_NORMALCOLOR;

   colorsel = (GtkColorSelectionDialog *)create_colorseldlg(sdata);
   gtk_color_selection_set_current_color(GTK_COLOR_SELECTION(colorsel->colorsel),
	 &(sdata->normal));
   gtk_widget_show(GTK_WIDGET(colorsel));

}



/*
 *
 * This callback is activated when the user chooses the
 * option 'set input font color' from the pulldown menu
 *
 */
void on_set_background_color_activate (GtkMenuItem *menuitem,
      gpointer user_data)
{
   GtkColorSelectionDialog *colorsel;
   Gtk_sdata *sdata;
   
   sdata   = (Gtk_sdata *)user_data;
   sdata->command = SET_BGCOLOR;

   colorsel = (GtkColorSelectionDialog *)create_colorseldlg(sdata);
   gtk_color_selection_set_current_color(GTK_COLOR_SELECTION(colorsel->colorsel),
	 &(sdata->in_fore));
   gtk_widget_show(GTK_WIDGET(colorsel));

}

/*
 *
 * This callback is activated when the user chooses the
 * option 'set font' from the pulldown menu
 *
 */
void on_set_font_activate (GtkMenuItem *menuitem,
      gpointer user_data)
{

   GtkWidget *fontsel;
   Gtk_sdata *sdata;
   

   sdata   = (Gtk_sdata *)user_data;
   sdata->command = SET_FONT;
   fontsel = create_fontseldlg(sdata);
   gtk_widget_show(fontsel);

}


/*
 * clears the screen. This will remove all text from the
 * screen
 *
 */
void on_clear_screen_activate (GtkMenuItem *menuitem,
      gpointer user_data)
{

   GtkTextView *gtext;
   Gtk_sdata *sdata;

   sdata = (Gtk_sdata *)user_data;
   gtext = (GtkTextView *)sdata->textw;
   gtk_text_buffer_set_text(gtk_text_view_get_buffer(gtext),
	 " ", -1);

}



/*
 *
 * Turns on the verbose mode for the game
 *
 */
void on_verbose_mode_activate (GtkMenuItem *menuitem,
      gpointer user_data)
{

   GtkCheckMenuItem *mit;
   Gtk_sdata *sdata;

   sdata   = (Gtk_sdata *)user_data;
   mit = (GtkCheckMenuItem *)menuitem;

   if(sdata->sgame != NULL
	 && sc_is_game_running(sdata->sgame)) {
      sc_set_game_verbose(sdata->sgame, mit->active);
      sdata->verbose = mit->active;
   }
}



/*
 *
 * This will undo one last command. It is called when the
 * 'Undo' is selected from the Game options
 */
void on_undo_activate (GtkMenuItem *menuitem,
      gpointer user_data)
{
   Gtk_sdata *sdata;
   GtkWidget *info;

   sdata   = (Gtk_sdata *)user_data;

   if(sdata->sgame != NULL
	 && sc_is_game_running(sdata->sgame)) {
      if(sc_is_game_undo_available(sdata->sgame))
	 sc_undo_game_turn(sdata->sgame);
      else {
	 info = create_about_dlg("Oops!",
	       "Undo not available right now!\n");
	 gtk_widget_show(info);
      }
	 
   }
   else {
      info = create_about_dlg("Hmmm..",
	    "No game seems to be running now!\n");
      gtk_widget_show(info);
   }
      

}






/*
 *
 * This will search the game directory for a text file & display it.
 * First it tries to find a file named 'gamename'.txt, where
 * gamename.taf is the actual game name. This search will ignore
 * case. Next, it will try to find a file called readme.txt. If still
 * no file is found, then it tries to find a file with extension
 *  '.txt'. If a file is found in any of the above searches, it is
 *  opened and shown.
 * 
 */
void on_gameinfo_activate (GtkMenuItem *menuitem,
      gpointer user_data)
{
   Gtk_sdata *sdata;
   GtkWidget *info;
   GtkTextView *tview;
   GtkTextBuffer *tbuf;
   GtkTextIter giter;
   
   char *cptr;
   char *cp;
   char dirname[1024];
   char fname[1024];
   char *tmpname;

   int i;
   int done;
   int len;

   DIR *tdir;

   struct dirent *direntry;
   struct stat fstat;
   
   FILE *fptr;
 
   sdata   = (Gtk_sdata *)user_data;

   if(sdata->sgame == NULL
	 || !sc_is_game_running(sdata->sgame)) {
      info = create_about_dlg("Hmmm..",
	    "No game seems to be running now!\n");
      gtk_widget_show(info);
      return;
   }

   cptr = strrchr(sdata->gname, '/');
   if(NULL != cptr)
   {
      i  = 0;
      cp = sdata->gname;
      while(cp != cptr)
	 dirname[i++] = *cp++;
      dirname[i] = '\0';
   }
   else
      strcpy(dirname, ".");

   cptr = strrchr(sdata->gname, '.');
   if(NULL != cptr)
   {
      i  = 0;
      cp = sdata->gname;
      while(cp != cptr)
	 fname[i++] = *cp++;
      fname[i] = '\0';
      strcat(fname, ".txt");
   }
   else
      strcpy(fname, ".");
   

   tdir = opendir(dirname);
   if(NULL == tdir)
      return;

   // Try to find a gamename.txt file.
   done = 0;
   while(!done)
   {
      direntry = readdir(tdir);
      if(NULL == direntry) {
	 break;
      }

      // Skip directories
      if(direntry->d_name[0] == '.')
	 continue;

      // Allocate memory for the full name
      tmpname = (char *) malloc(strlen(direntry->d_name)+strlen(dirname)+2);
      if(NULL == tmpname) {
	 break;
      }

      sprintf(tmpname, "%s/%s", dirname, direntry->d_name);
      stat(tmpname, &fstat);

      if(S_ISDIR(fstat.st_mode)) {
	 free(tmpname);
	 continue;
      }

      if(sc_strcasecmp(fname, tmpname) == 0) {
	 strcpy(fname, tmpname);
	 done = 1;
      }
      free(tmpname);

   }

   // Second attempt: try to find a 'readme.txt' file
   if(!done)
   {
      rewinddir(tdir);
      strcpy(fname, "readme.txt");
      while(!done)
      {
	 direntry = readdir(tdir);
	 if(NULL == direntry) {
	    break;
	 }

	 // Skip directories
	 if(direntry->d_name[0] == '.')
	    continue;

	 // Allocate memory for the full name
	 tmpname = (char *) malloc(strlen(direntry->d_name)+strlen(dirname)+2);
	 if(NULL == tmpname) {
	    break;
	 }

	 sprintf(tmpname, "%s/%s", dirname, direntry->d_name);
	 stat(tmpname, &fstat);

	 if(S_ISDIR(fstat.st_mode)) {
	    free(tmpname);
	    continue;
	 }

	 if(sc_strcasecmp(fname, direntry->d_name) == 0) {
	    strcpy(fname, tmpname);
	    done = 1;
	 }
	 free(tmpname);

      }
   }

   // Third and final attempt: Look for a file with readme in
   // the name, or walkthrough in the name, or a file with
   // '.txt' extension
   if(!done) {

      rewinddir(tdir);
      while(!done)
      {
	 direntry = readdir(tdir);
	 if(NULL == direntry) {
	    break;
	 }

	 // Skip directories
	 if(direntry->d_name[0] == '.')
	    continue;

	 // Allocate memory for the full name
	 tmpname = (char *) malloc(strlen(direntry->d_name)+strlen(dirname)+2);
	 if(NULL == tmpname) {
	    break;
	 }

	 sprintf(tmpname, "%s/%s", dirname, direntry->d_name);
	 stat(tmpname, &fstat);

	 if(S_ISDIR(fstat.st_mode)) {
	    free(tmpname);
	    continue;
	 }

	 len = strlen(direntry->d_name);
	 for(i=0; i<len; i++)
	    fname[i] = tolower(direntry->d_name[i]);
	 fname[i] = '\0';
	 
	 if(NULL != strstr(fname, "readme")
	       || NULL != strstr(fname, "walkthrough")
	       || NULL != strstr(fname, ".txt"))
	 {
	    strcpy(fname, tmpname);
	    done = 1;
	 }
	 free(tmpname);

      }
   }


   closedir(tdir);
   if(!done) {
      info = create_about_dlg("Hmmm..",
	    "No readme could be found.\n");
      gtk_widget_show(info);
      return;

   }

   fptr = fopen(fname, "ra");
   if(NULL == fptr) {
      sprintf(dirname, "Could not open the file %s\n", fname);
      info = create_about_dlg("Oh No!", dirname);
      gtk_widget_show(info);
      return;
   }

   sprintf(dirname, "Readme for %s", sc_get_game_name(sdata->sgame));
   info  = create_game_text_window(dirname);
   tview = (GtkTextView *)lookup_widget(info, "game_info_textview");
   
   tbuf = gtk_text_view_get_buffer(tview);
   gtk_text_buffer_get_end_iter(tbuf, &giter);

   while(!feof(fptr)) {
      done = fread(&dirname, 1, 255, fptr);
      gtk_text_buffer_insert(tbuf, &giter, dirname, done);
      if(done < 255)
	 break;
   }

   fclose(fptr);
   gtk_widget_show(info);


   

}




/*
 *
 * This will enable/disable input logging
 *
 */
void on_log_input_activate (GtkMenuItem *menuitem,
      gpointer user_data)
{
   Gtk_sdata *sdata;
   GtkWidget *info;

   sdata   = (Gtk_sdata *)user_data;
   if(sdata->log == NULL) {
      sdata->log = fopen("gtkscare_log.txt", "a");
      sdata->debuglog = fopen("gtkscare_debug_log.txt", "a");
      info = create_about_dlg("Input logging enabled.",
	    "Input logging has been enabled. Both normal inputs and the inputs in the debugging console will now be logged.\n");
      gtk_widget_show(info);
   }
   else {
      fclose(sdata->log);
      fclose(sdata->debuglog);
      sdata->log = NULL;
      sdata->debuglog = NULL;
      
      info = create_about_dlg("Input logging disabled",
	    "Input logging has been turned off.\n");
      gtk_widget_show(info);

   }

}


/*
 *
 * This will activate/deactivate the debugger. It is called
 * when 'Enable debugger' is selected from the Game options
 *
 */
void on_enable_debugger_activate (GtkMenuItem *menuitem,
      gpointer user_data)
{
   GtkCheckMenuItem *mit;
   Gtk_sdata *sdata;
   GtkWidget *info;

   sdata   = (Gtk_sdata *)user_data;
   mit = (GtkCheckMenuItem *)menuitem;

   if(sdata->sgame != NULL
	 && sc_is_game_running(sdata->sgame))
   {
      sc_set_game_debugger_enabled(sdata->sgame, mit->active);
      if(sc_get_game_debugger_enabled(sdata->sgame))
      {
	 info = create_about_dlg("Debugger Enabled",
	       "Debugger enabled. You may now bring up the debugger by typing 'debug' on the commandline, or you could now use the debugging console.\n");
	 gtk_widget_show(info);

      }
      else {
	 info = create_about_dlg("Debugger Disabled",
	       "The debugger has been disabled.\n");
	 gtk_widget_show(info);
      }
   }
   else {
      info = create_about_dlg("Hmmm..",
	    "No game seems to be running now!\n");
      gtk_widget_show(info);
   }



}



/*
 *
 * This callback is called when the user tries to activate the
 * debugger console from the game options menu
 *
 *
 */
void on_debugger_console_activate (GtkMenuItem *menuitem,
      gpointer user_data)
{
   GtkCheckMenuItem *mit;
   Gtk_sdata *sdata;
   GtkWidget *info;

   sdata   = (Gtk_sdata *)user_data;
   mit = (GtkCheckMenuItem *)menuitem;

   if(sdata->sgame == NULL
	 && !sc_is_game_running(sdata->sgame)) {
      info = create_about_dlg("Hmmm..",
	    "No game seems to be running now!\n");
      gtk_widget_show(info);
      return;
   }

   if(!sc_get_game_debugger_enabled(sdata->sgame)) {
      info = create_about_dlg("Whoops!",
	    "Please enable the debugger first.\n");
      gtk_widget_show(info);
      return;
   }

   info = create_debug_window ();
   gtk_widget_show(info);
   sdata->debugger = info;


}





/*
 * This callback is called when 'Usual commands' menu
 * option is selected from the main GUI.
 *
 */
void on_usual_commands_activate (GtkMenuItem *menuitem,
      gpointer user_data)
{
   GtkWidget *about;
   about = create_about_dlg("Command help",
	 "<b>These are the usual commands:\n\ne, w, n, s, se</b> : Go east, west, north, south, southeast (and similar combinations such as nw, ne).\n\n<b>Examining surroundings:</b> eXamine xx, Look , Look (at, under, through, in, behind) xx, search.\n\n<b>Manipulating things:</b> push xx, pull xx, put xx, get xx, drop xx, throw xx, use xx, read xx, etc.\n\n<b>Communicating:</b> show xx to xx, tell xx about xx, ask xx about xx, talk to xx, xx do xx etc.\n\n<b>Miscellaneous:</b> g (repeat action), z (wait), q (quit), <b>save (save game), load or restore (load a saved game),</b> restart (restart game), undo (undo previous command), verbose (verbose mode).");
   gtk_widget_show(about);

}


/*
 *
 * This callback is called when 'about' menu option is selected.
 *
 */
void on_about_gtkscare_activate  (GtkMenuItem *menuitem,
      gpointer user_data)
{
   GtkWidget *about;

   about = create_aboutdlg((Gtk_sdata *)user_data);
   gtk_widget_show(about);

}



/*
 *
 * Called when 'ok' button of fileselector dialog is clicked
 *
 */
void on_fsel_ok_butn_clicked (GtkButton *button,
      gpointer user_data)
{
   Gtk_sdata *sdata;
   GtkWidget *fsel;
   GtkWidget *warn;
   GtkTextBuffer *tbuf;
   GtkTextIter giter;
   
   const char *fname;

   int tflags;
   
   sdata = (Gtk_sdata *)user_data;
   fsel  = sdata->curw;
   fname = gtk_file_selection_get_filename(GTK_FILE_SELECTION(fsel));

   if(NULL == fname
	 || fname[strlen(fname)-1] == '/')
      return;

   strcpy(sdata->name, fname);
   sdata->yesno = DYES;

   tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(sdata->textw));
   gtk_text_buffer_get_end_iter(tbuf, &giter);
   gtk_text_buffer_insert(tbuf, &giter, "\nOpening file ", -1);
   gtk_text_buffer_insert(tbuf, &giter, fname, -1);
   gtk_text_buffer_insert(tbuf, &giter, "\n", -1);


   if(sdata->menu)
   {
      tflags = 0;
      switch(sdata->command) {

	 case OPEN_GAME:
	    sdata->sgame = sc_game_from_filename(sdata->name, tflags);
	    if(sdata->sgame == NULL) {
	       warn = create_about_dlg("Game opening failure!",
		     "Sorry, there was an error opening the game.");
	       sdata->yesno = DNO;
	       break;
	    }
	    strcpy(sdata->gname, sdata->name);
	    break;

	 case SAVE_GAME:
	    if(NULL != sdata->sgame)
	       sc_save_game(sdata->sgame);
	    break;

	 case LOAD_SAVEFILE:
	    if(NULL != sdata->sgame)
	       sc_load_game(sdata->sgame);
	    break;

	 default:
	    break;
      }
		  
   }
   gtk_widget_destroy(fsel);

}


void on_fsel_cancel_butn_clicked (GtkButton *button,
      gpointer user_data)
{
   Gtk_sdata *sdata;
   
   sdata = (Gtk_sdata *)user_data;
   sdata->yesno = DNO;

   gtk_widget_destroy(sdata->curw);

}


/*
 *
 * This callback is called when the 'ok' button in the
 * color selector dialog is clicked.
 *
 */
void on_colorsel_ok_clicked (GtkButton *button,
      gpointer user_data)
{

   GtkColorSelectionDialog *gsd;
   Gtk_sdata *sdata;
   GdkColor gdcol;

   sdata = (Gtk_sdata *)user_data;
   gsd   = (GtkColorSelectionDialog *)sdata->curw;

   switch(sdata->command)
   {
      case SET_NORMALCOLOR:
	 gtk_color_selection_get_current_color((GtkColorSelection *)gsd->colorsel,
	       &(sdata->normal));
	 gtk_widget_modify_text(GTK_WIDGET(sdata->textw),
	       GTK_STATE_NORMAL,
	       &(sdata->normal));
	 break;

      case SET_BGCOLOR:
	 gtk_color_selection_get_current_color((GtkColorSelection *)gsd->colorsel,
	       &(sdata->in_fore));
	 gtk_widget_modify_base(GTK_WIDGET(sdata->textw),
	       GTK_STATE_NORMAL,
	       &(sdata->in_fore));
	 break;

      case SET_INPUTCOLOR:
	 gtk_color_selection_get_current_color((GtkColorSelection *)gsd->colorsel,
	       &gdcol);
	 gdk_color_alloc(gtk_widget_get_colormap(sdata->textw), &gdcol);
	 gdk_window_set_background(sdata->textw->window,
	       &gdcol);
	 break;
   }

   
   gtk_widget_destroy(sdata->curw);

}


/*
 *
 * This callback is called when the 'cancel' button in the
 * color selector dialog is clicked.
 *
 */
void on_colorsel_cancel_clicked (GtkButton *button,
      gpointer user_data)
{

   Gtk_sdata *sdata;
   sdata = (Gtk_sdata *)user_data;
   gtk_widget_destroy(sdata->curw);

}



/*
 *
 * called when the ok button is font selector dialog is activated
 *
 */
void on_fontsel_ok_clicked (GtkButton *button,
      gpointer user_data)
{

   GtkFontSelectionDialog *gfd;
   Gtk_sdata *sdata;
   PangoFontDescription *pdes;
   
   sdata = (Gtk_sdata *)user_data;
   gfd   = (GtkFontSelectionDialog *)sdata->curw;

   strcpy(fstring,
	 gtk_font_selection_dialog_get_font_name(gfd));
   pdes = pango_font_description_from_string(fstring);
   gtk_widget_modify_font(sdata->textw, pdes);

   pango_font_description_free(pdes);

   gtk_widget_destroy(sdata->curw);

}


/*
 *
 * called when the cancel button is font selector dialog is activated
 *
 */
void on_fontsel_cancel_clicked (GtkButton *button,
      gpointer user_data)
{

   Gtk_sdata *sdata;
   
   sdata = (Gtk_sdata *)user_data;
   gtk_widget_destroy(sdata->curw);

}


/*
 *
 * called when the apply button is font selector dialog is activated
 *
 */
void on_fontsel_apply_clicked (GtkButton *button,
      gpointer user_data)
{

   GtkFontSelectionDialog *gfd;
   Gtk_sdata *sdata;
   PangoFontDescription *pdes;
   
   sdata = (Gtk_sdata *)user_data;
   gfd   = (GtkFontSelectionDialog *)sdata->curw;

   strcpy(fstring,
	 gtk_font_selection_dialog_get_font_name(gfd));
   pdes = pango_font_description_from_string(fstring);
   gtk_widget_modify_font(sdata->textw, pdes);

   pango_font_description_free(pdes);

}


/*
 * This is called when 'I see' button on the about dialogbox is clicked.
 *
 */
void on_button3_clicked (GtkButton *button,
      gpointer user_data)
{

   gtk_widget_destroy(GTK_WIDGET(user_data));
}


void on_dlg_yes_butn_clicked (GtkButton *button,
      gpointer user_data)
{
   Gtk_sdata *sdata;
   
   sdata = (Gtk_sdata *)user_data;
   sdata->yesno = DYES;

   gtk_widget_destroy(sdata->curw);

}


void on_dlg_no_butn_clicked (GtkButton *button,
      gpointer user_data)
{

   Gtk_sdata *sdata;
   GtkTextBuffer *tbuf;
   GtkTextIter giter;
   
   sdata = (Gtk_sdata *)user_data;
   sdata->yesno = DNO;

   tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(sdata->textw));
   gtk_text_buffer_get_end_iter(tbuf, &giter);
   gtk_text_buffer_insert(tbuf, &giter, "\nSmart. Verrry smart\n", -1);
   gtk_widget_destroy(sdata->curw);
}


gboolean on_widget_delete( GtkButton *button,
      GdkEvent *event,
      gpointer user_data)
{

   Gtk_sdata *sdata;
   
   sdata = (Gtk_sdata *)user_data;
   sdata->yesno = DNO;
   return FALSE;
}

/*
 *
 * This handler is called when a key is pressed in the
 * entry widget
 *
 */
gboolean on_key_press(GtkEntry *entry,
      GdkEventKey *kevent,
      gpointer user_data)
{
   Gtk_sdata *sdata;
   sdata = (Gtk_sdata *)user_data;

   if(kevent->keyval == GDK_Up )
   {
      if(sdata->spoint == sdata->ipoint)
	 sdata->spoint--;
      gtk_entry_set_text(entry, sdata->cmds[sdata->spoint]);
      sdata->spoint--;

      if(sdata->num_cmds >= CMDBUF) {
	 if(sdata->spoint == sdata->ipoint)
	    sdata->spoint++;
	 else if(sdata->spoint < 0)
	    sdata->spoint = CMDBUF-1;
      }
      else if(sdata->spoint < 0)
	 sdata->spoint = 0;

      gtk_editable_set_position(GTK_EDITABLE(entry), -1);
      gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event");
      return TRUE;
   }
   else if(kevent->keyval == GDK_Down)
   {
      gtk_entry_set_text(entry, sdata->cmds[sdata->spoint]);
      sdata->spoint++;

      if(sdata->num_cmds >= CMDBUF) {
	 if(sdata->spoint == sdata->ipoint) {
	    sdata->spoint--;
	    gtk_entry_set_text(entry, "");
	 }
	 else if(sdata->spoint >= CMDBUF-1) {
	    sdata->spoint = 0;
	 }
      }
      else if(sdata->spoint > sdata->ipoint) {
	 sdata->spoint = sdata->ipoint;
	 gtk_entry_set_text(entry, "");
      }

      gtk_editable_set_position(GTK_EDITABLE(entry), -1);
      gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event");
      return TRUE;

   }
   else if(sdata->command == WAIT_FOR_KEY) {
      gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event");
      sdata->got_input = 1;
      return TRUE;
   }

	 
   
   return FALSE;
 

}



/*
 *
 * This callback is called when the user hits the 'show hint'
 * button in the hint dialogbox.
 *
 */
void on_hintbutton_clicked (GtkButton *button,
      gpointer user_data)
{

   GtkTextView *tview;
   GtkTreeView *treeview;
   GtkTextBuffer *tbuf;
   Gtk_sdata *sdata;
   GtkTreeSelection *selection;
   GtkTreeIter iter;
   GtkTreeModel *model;
   int val;

   sdata = (Gtk_sdata *)user_data;
   tview = (GtkTextView *)lookup_widget(GTK_WIDGET(button), "hintview");
   treeview = (GtkTreeView *)lookup_widget(GTK_WIDGET(button), "htreeview");
   tbuf  = gtk_text_view_get_buffer(tview);
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));

   if(gtk_tree_selection_get_selected(selection, &model, &iter))
   {
      gtk_tree_model_get (model, &iter, 0, &val, -1);
      gtk_text_buffer_set_text(tbuf,
	    sc_get_game_subtle_hint(sdata->sgame, sdata->shint[val-1]), -1);

   }


}



/*
 *
 * This callback is called when the user hits the 'show solution'
 * button in the hint dialogbox.
 *
 */
void on_solbutton_clicked (GtkButton *button,
      gpointer user_data)
{

   GtkTextView *tview;
   GtkTreeView *treeview;
   GtkTextBuffer *tbuf;
   Gtk_sdata *sdata;
   GtkTreeSelection *selection;
   GtkTreeIter iter;
   GtkTreeModel *model;
   int val;

   sdata = (Gtk_sdata *)user_data;
   tview = (GtkTextView *)lookup_widget(GTK_WIDGET(button), "hintview");
   treeview = (GtkTreeView *)lookup_widget(GTK_WIDGET(button), "htreeview");
   tbuf  = gtk_text_view_get_buffer(tview);
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));

   if(gtk_tree_selection_get_selected(selection, &model, &iter))
   {
      gtk_tree_model_get (model, &iter, 0, &val, -1);
      gtk_text_buffer_set_text(tbuf,
	    sc_get_game_unsubtle_hint(sdata->sgame, sdata->shint[val-1]),
	    -1);

   }

}


