/* Cursors.c  -- This stuff handles animated cursors for Tk/Tcl */
/*   by Ray R. Larson  - Aug 1992                               */
/*   based on the spinning world cursor in the XWAIS program    */
#include <stdio.h>
#include "tcl.h"
#include "tk.h"
#include "tkConfig.h"
#include "tkInt.h"
#include <signal.h>


/* names and count of the windows affected when changing cursors */
static int worldcursoron = 0;
static int cursor_win_countp;
static char **cursor_win_namep;
#define MAXWINDOWS 50
static int num_curs_windows;
static Tk_Window curs_windows[MAXWINDOWS];
/* names and count of the windows affected */
static void set_cursors();
static int cursors_loaded = 0;


#define w_width 16
#define w_height 16
#define w_hotx 8
#define w_hoty 8

static char wmask_bits[] = {
   0xc0, 0x03, 0xf0, 0x0f, 0xfc, 0x3f, 0xfe, 0x7f, 0xfe, 0x7f, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x7f,
   0xfc, 0x3f, 0xf8, 0x1f, 0xf0, 0x0f, 0xc0, 0x03};

static char w0_bits[] = {
   0xff, 0xff, 0xff, 0xfc, 0xbf, 0xf1, 0x67, 0xe3, 0xe3, 0xc5, 0xe3, 0xc6,
   0xe1, 0x83, 0xc1, 0x83, 0x81, 0x85, 0x01, 0x81, 0x03, 0xcf, 0x03, 0xcf,
   0x07, 0xe6, 0x0f, 0xf6, 0x3f, 0xfe, 0xff, 0xff};

static char w1_bits[] = {
   0xff, 0xff, 0x1f, 0xff, 0x1f, 0xfd, 0x0f, 0xfb, 0x0b, 0xef, 0x07, 0xf7,
   0x07, 0x9f, 0x07, 0x9e, 0x03, 0xac, 0x01, 0x88, 0x13, 0xf8, 0x3f, 0xf8,
   0x3f, 0xf0, 0x0f, 0xf0, 0x3f, 0xfc, 0xff, 0xff};

static char w2_bits[] = {
   0xff, 0xff, 0xff, 0xfd, 0xbf, 0xf0, 0xff, 0xe0, 0xbf, 0xc0, 0x7f, 0xc0,
   0x7f, 0x80, 0x7f, 0x80, 0x3f, 0x80, 0x15, 0x80, 0x23, 0xc1, 0x8b, 0xc3,
   0xc7, 0xe3, 0x0f, 0xf0, 0x3f, 0xfc, 0xff, 0xff};

static char w3_bits[] = {
   0xff, 0xff, 0x1f, 0xff, 0xff, 0xf5, 0xff, 0xe7, 0xff, 0xc5, 0xf9, 0xc3,
   0xfb, 0x83, 0xf7, 0x83, 0xf7, 0x81, 0xa7, 0x80, 0x03, 0xc9, 0x47, 0xdc,
   0x07, 0xfe, 0x0f, 0xf0, 0x3f, 0xfc, 0xff, 0xff};

static char w4_bits[] = {
   0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc5, 0xff,
   0xb9, 0xbf, 0x7d, 0xbf, 0x7d, 0x9f, 0x3d, 0x8a, 0x3b, 0xd0, 0x5f, 0xc0,
   0x1f, 0xf0, 0x0f, 0xf0, 0x3f, 0xfc, 0xff, 0xff};

static char w5_bits[] = {
   0xff, 0xff, 0x3f, 0xff, 0xc7, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0x43, 0xfc,
   0x83, 0xbb, 0xc5, 0xb7, 0xc1, 0x97, 0xc3, 0x83, 0x8f, 0xc3, 0x8f, 0xc5,
   0x83, 0xe1, 0x0f, 0xf0, 0x3f, 0xfc, 0xff, 0xff};

static char w6_bits[] = {
   0xff, 0xff, 0xff, 0xfc, 0x7f, 0xfc, 0x6f, 0xfc, 0xbf, 0xfc, 0xdf, 0xc8,
   0x7d, 0xf0, 0x79, 0xf8, 0xb1, 0xf8, 0x21, 0xf8, 0xe3, 0xf1, 0xe3, 0xf1,
   0xc7, 0xf0, 0xcf, 0xf0, 0xff, 0xf9, 0xff, 0xff};

static char *cursorbitmaps[] = { 
   w0_bits, w1_bits, w2_bits, w3_bits, w4_bits, w5_bits, w6_bits};


#define NUMCURSORS 7
Cursor worldcursors[NUMCURSORS];
extern Tcl_Interp *interp;			/* Current interpreter. */


/***********************************/
void LoadWorldCursors(mainwin)
 Tk_Window mainwin;
{

  Pixmap maskpm, cursorpm;
  XColor fg, bg;
  int i;
  if (mainwin) { /* main window exists */
    maskpm = XCreatePixmapFromBitmapData(Tk_Display(mainwin), Tk_WindowId(mainwin),
            wmask_bits, w_width, w_height, 1, 0, 1);

    fg.red = 0; fg.green = 0xaaaa; fg.blue = 0x0444;
    bg.red = 0; bg.green = 0; bg.blue = 0xffff;
  
    for (i=0;i<NUMCURSORS;i++) {
      cursorpm = XCreatePixmapFromBitmapData(Tk_Display(mainwin), Tk_WindowId(mainwin),
            cursorbitmaps[i], w_width, w_height, 1, 0, 1);
       worldcursors[i] = XCreatePixmapCursor(Tk_Display(mainwin),
	     cursorpm, maskpm, &fg, &bg, w_hotx, w_hoty);
    }
    cursors_loaded = 1;
  }
  else fprintf (stderr, "Main window doesn't exist in LoadWorldCursors");
}

static int cursorframeno=0;


/***********************************/
void WaitCursor(mainwin, interp)
 Tk_Window mainwin;
 Tcl_Interp *interp;
{
  if (!cursors_loaded) LoadWorldCursors(mainwin);
  SetCursors(mainwin, interp, cursorframeno);
  cursorframeno = (cursorframeno+1) % NUMCURSORS;
}


/***********************************/
int SetCursors(mainwin, interp, n)
 Tk_Window mainwin;
 Tcl_Interp *interp;
 int n;
{
  Cursor c;
  if (n < 0) {
    c = Tk_GetCursor(interp, mainwin, Tk_GetUid("top_left_arrow") );
    set_cursors(mainwin,c,c);
  }
  else {
    c = worldcursors[n%NUMCURSORS];
    set_cursors(mainwin, c,c);
  }
  XFlush(Tk_Display(mainwin));
}
  

static void set_cursors(mainwin, mainc, otherc)
     Tk_Window mainwin;
     Cursor mainc, otherc;
{
  int i;
  if (mainwin) XDefineCursor(Tk_Display(mainwin), Tk_WindowId(mainwin), mainc);
  for (i=0; i < num_curs_windows; i++) {
    if(curs_windows[i] != NULL) {
      XDefineCursor(Tk_Display(curs_windows[i]), 
		    Tk_WindowId(curs_windows[i]), otherc);
    }
  }
}

int
MakeWindowList(mainwin, interp)
 Tk_Window mainwin;
 Tcl_Interp *interp;
{
  int i, result ;
  char *windowlist, *msg;

  result = Tcl_VarEval(interp, "global CURSWINDOWS ", (char *) NULL);
  result = Tcl_VarEval(interp, 
		       "set CURSWINDOWS [winfo children .]", (char *) NULL);
  if (result != TCL_OK) {
    fprintf(stderr, "In MakeWindowList: couldn't get winfo\n");
  }
  windowlist = Tcl_GetVar(interp, "CURSWINDOWS", TCL_GLOBAL_ONLY);
  if (windowlist == NULL) {
    msg = interp->result;
    fprintf(stderr, "In MakeWindowList: %s\n",msg);
  }
  Tcl_SplitList(interp,windowlist, &cursor_win_countp, &cursor_win_namep);
  
  /* ok, should now have the current list of window names, so, put */
  /* their handles into the global array */
  for (i=0; i < cursor_win_countp; i++) {
    if (i < MAXWINDOWS) 
      curs_windows[i] = Tk_NameToWindow(interp, cursor_win_namep[i], mainwin);  
  }
  num_curs_windows = i;
}




/************** set mouse cursor as spinning world globe  *******************/
int
WaitCursorCmd(tkwin, interp, argc, argv)
    Tk_Window tkwin;			/* all params ignored */
    Tcl_Interp *interp;			/* Current interpreter. */
    int argc;				/* Number of arguments. */
    char **argv;			/* Argument strings. */
{

  Tk_Window mainwin;

  mainwin = Tk_MainWindow(interp);
  if (worldcursoron) WaitCursor(mainwin, interp);
  else {
    MakeWindowList(mainwin, interp);
    WaitCursor(mainwin, interp);
    worldcursoron = 1;
  }
  return TCL_OK;
}

int
NormalCursorCmd(tkwin, interp, argc, argv)
    Tk_Window tkwin;			/* all params ignored */
    Tcl_Interp *interp;			/* Current interpreter. */
    int argc;				/* Number of arguments. */
    char **argv;			/* Argument strings. */
{

  Tk_Window mainwin;

  mainwin = Tk_MainWindow(interp);
  
  if (worldcursoron) SetCursors(mainwin, interp, -1);
  worldcursoron = 0;

  return TCL_OK;
}


