
/*
 * xanim_x11.c
 *
 * Copyright (C) 1990,1991,1992 by Mark Podlipec. 
 * All rights reserved.
 *
 * This software may be freely copied, modified and redistributed
 * without fee provided that this copyright notice is preserved 
 * intact on all copies and modified copies.
 * 
 * There is no warranty or other guarantee of fitness of this software.
 * It is provided solely "as is". The author(s) disclaim(s) all
 * responsibility and liability with respect to this software's usage
 * or its effect upon hardware or computer systems.
 *
 */

#include <X11/Xlib.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/times.h>
#include <memory.h>
#include <ctype.h>
#include "mytypes.h"
#include "xanim.h"
#include "xanim_x11.h"
 
void xanim_expose();
void xanim_key();
void xanim_quit();
void xanim_events();
void X11Setup();

/*********************************** X11 stuff */
Display       *theDisp;
Visual        *theVisual;
Colormap       theCmap;
Window         mainW;
GC             theGC;
XImage        *theImage;
XColor         defs[256];
/******************************** Xt stuff */
XtAppContext  theContext;

#define ACTIONTABLE_SIZE 4
XtActionsRec actionTable[] = {
        {"Expose", xanim_expose},
        {"Quit", xanim_quit},
        {"Key", xanim_key},
        {"Go", ShowAnimation}
};

static struct _resource {
  int anim;
} resource;

#define offset(field)   XtOffset(struct _resource *, field)

XtResource application_resources[] = {
  {"anim", "Anim", XtRBoolean, sizeof (Boolean),
     offset(anim), XtRString, "False" },
};

String   Translation =
"<Expose>:Expose()\n\
<Key>:Key()";


void X11_Pre_Setup()
{
 int i,vis_num;
 XVisualInfo *vis;
 
 XtToolkitInitialize();
 theContext = XtCreateApplicationContext();
 XtAppAddActions(theContext, actionTable, ACTIONTABLE_SIZE);

 i = 0;
 theDisp = XtOpenDisplay(theContext, NULL, "xanim", "XAnim",NULL,0,&i,NULL);
 if (theDisp==NULL) 
 {
  TheEnd1("Unable to open display\n"); 
 }

 x11_depth = DefaultDepth(theDisp, DefaultScreen(theDisp));

 theVisual = DefaultVisual(theDisp, DefaultScreen(theDisp));
 x11_class = theVisual->class;
 if ( (x11_class == PseudoColor) && (x11_depth <=8) && (x11_depth >=1) )
 {
  x11_bytes_pixel = 1;
  x11_cmap_flag = TRUE;
  x11_display_type = PSEUDO_COLOR_8BIT;
 }
 else if ( (x11_class == TrueColor) && (x11_depth == 24) )
      {
       x11_bytes_pixel = 4;
       x11_cmap_flag = FALSE;
       x11_display_type = TRUE_COLOR_24BIT;
      }
      else /* not yet supported */
      {
       fprintf(stderr,"Unsupported Visual class=%ld depth=%ld \n",
		x11_class,x11_depth);
       TheEnd();
      }

 x11_cmap_size = DisplayCells(theDisp, DefaultScreen(theDisp));


#ifdef X11_VERBOSE
 fprintf(stderr,"Class = %ld depth=%ld bytes_pixel=%lx\n",
		x11_class,x11_depth,x11_bytes_pixel);
 fprintf(stderr,"x11_cmap_size = %ld\n",x11_cmap_size);
#endif


#ifdef X11_VERBOSE
 vis = XGetVisualInfo (theDisp, VisualNoMask, NULL, &vis_num);
 if ((vis == NULL) || (vis_num == 0) )
 {
  TheEnd1("X11: Couldn't get any Visuals\n");
 }
 else
 {
  for(i=0;i<vis_num;i++)
  {
   fprintf(stderr,"visual %ld) depth= %ld  class= %ld  ",
     i, vis[i].depth, vis[i].class, vis[i].colormap_size );
   fprintf(stderr,"%ld) class = %ld\n",i,vis[i].class);
   fprintf(stderr,"%ld) cmap sz = %ld\n",i,vis[i].colormap_size);
  }
 }
 XFree(vis);  
#endif

}

/*
 * Setup X11 Display, Window and Toolkit
 */
void X11_Setup(max_imagex,max_imagey,startx,starty)
int max_imagex,max_imagey;
int startx,starty;
{
 int i,off;
 Widget wg;
 int n;
 Arg arglist[20];



 n = 0;
 XtSetArg(arglist[n], XtNwidth, startx); n++;
 XtSetArg(arglist[n], XtNheight, starty); n++;
 XtSetArg(arglist[n], XtNmaxWidth, max_imagex); n++;
 XtSetArg(arglist[n], XtNmaxHeight, max_imagey); n++;
 wg = XtAppCreateShell("xanim", "XAnim", applicationShellWidgetClass, 
                        theDisp, arglist, n);

 XtGetApplicationResources (wg, &resource, application_resources,
                            XtNumber(application_resources), NULL, 0);

 XtRealizeWidget(wg);
 XtOverrideTranslations(wg, XtParseTranslationTable(Translation));

 mainW = XtWindow(wg);

 theImage = XCreateImage(theDisp,DefaultVisual(theDisp,DefaultScreen(theDisp)),
                            x11_depth,ZPixmap,0,0,max_imagex,max_imagey,
			    x11_bytes_pixel,(x11_bytes_pixel * max_imagex));

 theCmap   = DefaultColormap(theDisp, DefaultScreen(theDisp));  
 theGC     = DefaultGC(theDisp,DefaultScreen(theDisp));

 if (x11_cmap_flag == TRUE)
 {
   for(i=0;i<x11_cmap_size;i++) 
   {
      defs[i].pixel = i;
      defs[i].flags = DoRed | DoGreen | DoBlue;
   }
   XQueryColors(theDisp,DefaultColormap(theDisp, DefaultScreen(theDisp)),
                defs,x11_cmap_size);

   off = x11_cmap_size - imagec;
   for(i=0;i<imagec;i++)
   {
    defs[off+i].pixel = off+i;
    defs[off+i].red   = cmap[i].red   << 8;
    defs[off+i].green = cmap[i].green << 8;
    defs[off+i].blue  = cmap[i].blue  << 8;
    defs[off+i].flags = DoRed | DoGreen | DoBlue;
   }
   theCmap = XCreateColormap(theDisp,mainW,
                             DefaultVisual(theDisp, DefaultScreen(theDisp)),
                             AllocAll);
   if (theCmap==0) 
   {
    fprintf(stderr,"cmap==0 error\n");
   }
   XStoreColors(theDisp,theCmap,defs,x11_cmap_size);
   XInstallColormap(theDisp,theCmap);
   XSetWindowColormap(theDisp, mainW, theCmap);
 }

 XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask);

 XMapWindow(theDisp,mainW);
 XFlush(theDisp);
}

void xanim_expose(wg, event, str, np)
        Widget          wg;
        XExposeEvent   *event;
        String         *str;
        int            *np;
{
 if (   ( (anim_flags & ANIM_CYCLE) && cycle_on_flag && cycle_wait)
     || ( (anim_cnt == 1) && cycle_wait)
    )
 {
  XPutImage(theDisp,mainW,theGC,theImage,0,0,0,0,imagex,disp_y);
 }
}

void xanim_key(wg, event, str, np)
Widget          wg;
XKeyEvent      *event;
String         *str;
int            *np;
{
        char            buff[10];
        KeySym          ks;
        XComposeStatus  st;
 if (event->type == KeyPress)
 {
        XLookupString(event, buff, 10, &ks, &st);
	switch(buff[0])
	{
	 case 'q':
	 case 'Q': TheEnd();
		   break;
	 case 'g':
         case 'G': anim_flags &= (~ANIM_CYCLE);
		   break;
         case 's': 
         case 'S': 
		   if (cycle_on_flag) cycle_on_flag = 0;
		   else  cycle_on_flag = 1;
		   break;
	
         case 'r': 
         case 'R': 
		   {
		    int j,c_off;

		    c_off = x11_cmap_size-imagec;
                    for(j=0;j<imagec;j++)
                    {
                     defs[j].pixel = j+c_off;
                     defs[j].red   = cmap[j+c_off].red   << 8;
                     defs[j].green = cmap[j+c_off].green << 8;
                     defs[j].blue  = cmap[j+c_off].blue  << 8;
                     defs[j].flags = DoRed | DoGreen | DoBlue;
                    }
                    XStoreColors(theDisp,theCmap,defs,imagec);
 		    XFlush(theDisp);
		   }
		   break;
         case '.': 
		   if (anim_running==TRUE) anim_running = FALSE;
   		   else
		   {
		    anim_forward_flag = TRUE;
		    Step_Frame_Next();
  	            XtAppAddTimeOut(theContext, 1, ShowAction, NULL);
		   }
		   break;
         case ',': 
		   if (anim_running==TRUE) anim_running = FALSE;
   		   else
		   {
		    anim_forward_flag = FALSE;
		    Step_Frame_Prev();
  	            XtAppAddTimeOut(theContext, 1, ShowAction, NULL);
		   }
		   break;
         case '>': 
		   if (anim_running==TRUE) anim_running = FALSE;
   		   else
		   {
		    anim_forward_flag = TRUE;
		    Step_File_Next();
  	            XtAppAddTimeOut(theContext, 1, ShowAction, NULL);
		   }
		   break;
         case '<': 
		   if (anim_running==TRUE) anim_running = FALSE;
   		   else
		   {
		    anim_forward_flag = TRUE;
		    Step_File_Prev();
  	            XtAppAddTimeOut(theContext, 1, ShowAction, NULL);
		   }
		   break;
         case ' ': 
		   if (anim_running==TRUE) anim_running = FALSE;
   		   else
		   {
		    anim_running=TRUE;
		    Step_Action_Next();
  	            XtAppAddTimeOut(theContext, 1, ShowAction, NULL);
		   }
		   break;
         case 'm': 
		   anim_forward_flag = (anim_forward_flag==TRUE)?FALSE:TRUE;
		   break;
	}
 }
}

void xanim_quit(wg, event, str, np)
Widget          wg;
XKeyEvent      *event;
String         *str;
int            *np;
{
 TheEnd(); 
}

void xanim_events()
{
 XtAppMainLoop(theContext);
}
