/*
 GNU Maverik - a system for managing display and interaction in 
               Virtual Environment applications.
 Copyright (C) 1999 Advanced Interfaces Group

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA


 The authors can be contacted via:
 www   - http://aig.cs.man.ac.uk
 email - maverik@aig.cs.man.ac.uk
 mail  - Advanced Interfaces Group, Room 2.94, Computer Science Building, 
         University of Manchester, Manchester, M13 9PL, UK
*/


/* These are the only bits of Maverik we need. Keep interface to window
   manager as light as possible to make its easy for other implementation */

#define MAX_WINS 10 /* Make sure the same or greater than equivalent in mav_kernel.h */
#define MAX_FONTS 10 /* Same as above */
void mav_moduleNew(char *fn(void));
extern int mav_opt_bindTextures;
extern int mav_opt_shareContexts;
extern int mav_opt_maxTextures;
extern int mavlib_voodoo;
extern void *mavlib_dlh;



/* Only OpenGL is applicable for Windows and Macs */

#if defined(WIN32) || defined(macintosh)
#ifndef MAV_OPENGL
#define MAV_OPENGL
#endif
#endif



/* X, OpenGL and IrisGL includes as necessary */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if !defined(WIN32) && !defined(macintosh)
#include <dlfcn.h>
#endif

#ifndef MAV_NONE
#ifdef MAV_IRISGL
#include <X11/keysym.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <gl/glws.h>
#elif defined(macintosh)
#include <agl.h>
#include <Quickdraw.h>
#include <Fonts.h>
#include <Windows.h>
#include <Events.h>
#include <MacWindows.h>
#elif defined(WIN32)
#include <windows.h>
#include <GL/gl.h>
#else
#include <X11/keysym.h>
#include <GL/glx.h>
#endif

#ifdef GL_EXT_texture_object
extern GLuint *mavlib_bindTextureIndex;
#endif

#ifdef macintosh
WindowPtr mavlib_rootwin;
#elif defined(WIN32)
HINSTANCE mavlib_dpy;
LONG WINAPI mavlib_winEventHandler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam);
#else
Display *mavlib_dpy; 
Window mavlib_rootwin;
int mavlib_scrnum;
#endif



/* Data structure to store window and context of each MAV_window */

typedef struct {
#ifdef macintosh
  WindowPtr win;
  AGLContext ctx;
#elif defined(WIN32)
  HDC hdc;
  HWND win;
  HGLRC ctx;
  int width;
  int height;
  int resized;
#else
  Window win;
#ifdef MAV_IRISGL
#else
  GLXContext ctx;
#endif
#endif
} MAVLIB_winhand;

MAVLIB_winhand mavlib_winhand[MAX_WINS];
int mavlib_currwin;
#endif



#ifndef MAV_NONE
/* Routine to convert from OS's Window into MAV_window id */ 
#ifdef macintosh
int mavlib_winlookup(WindowPtr w)
#elif defined(WIN32)
int mavlib_winlookup(HWND w)
#else
int mavlib_winlookup(Window w)
#endif
{
  int i;
  
  for (i=0; i<MAX_WINS; i++) {
    if (mavlib_winhand[i].win==w) return i;
  }

  return -1;
}
#endif



/* Routines to initialise the graphics module */

char *mav_gfxModuleID(void)
{
#ifdef MAV_NONE
  return "Graphics (None)";
#elif defined(MAV_IRISGL)
  return "Graphics (IrisGL and X11)";
#elif defined(WIN32)
  return "Graphics (OpenGL and Windows)";
#elif defined(macintosh)
  return "Graphics (OpenGL and MacOS)";
#else
  if (mavlib_voodoo)
  {
    return "Graphics (OpenGL and X11, Voodoo detected)";
  }
  else
  {
    return "Graphics (OpenGL and X11)";
  }
#endif
}

void mavlib_gfxExit(void)
{
#ifndef MAV_NONE
  int i;
#ifdef WIN32
  /* shut down windows nicely */
  for (i=0; i<MAX_WINS; i++) {
    if (mavlib_winhand[i].win) {
      wglDeleteContext(mavlib_winhand[i].ctx);
      DestroyWindow(mavlib_winhand[i].win);
    }
  }
#elif defined(macintosh)
  /* shut down windows nicely */
  for (i=0; i<MAX_WINS; i++) {
    if (mavlib_winhand[i].win) {
       aglSetCurrentContext(NULL);
       aglSetDrawable(mavlib_winhand[i].ctx, NULL);
       aglDestroyContext(mavlib_winhand[i].ctx);
       DisposeWindow(mavlib_winhand[i].win);
    }
  } /* for */
#else
  /* turn on auto repeat */
  XAutoRepeatOn(mavlib_dpy);

  /* shut down windows nicely */
  for (i=0; i<MAX_WINS; i++) {
#ifdef MAV_OPENGL
#ifndef MAV_LINUX
    /* glXDestroyContext(mavlib_dpy, mavlib_winhand[i].ctx);*/
#endif
#endif
    if (mavlib_winhand[i].win) XDestroyWindow(mavlib_dpy, mavlib_winhand[i].win);
  }

  XSync(mavlib_dpy, False);
#endif
#endif
}

int mav_gfxModuleInit()
{
  char *voodoo;
#ifndef MAV_NONE
  /* Initialise data structure */
  int i;
#ifdef WIN32
  WNDCLASS wc;
  for (i=0; i<MAX_WINS; i++) mavlib_winhand[i].win= (HWND) NULL;
#elif defined(macintosh)
  for (i=0; i<MAX_WINS; i++) mavlib_winhand[i].win= (WindowPtr) NULL;
#else
  for (i=0; i<MAX_WINS; i++) mavlib_winhand[i].win= (Window) NULL;
#endif
#endif

  /* add the new module */
  mav_moduleNew(mav_gfxModuleID);  

#ifndef MAV_NONE
#ifdef macintosh
  	/* Initialize Macintosh system */
	InitGraf(&qd.thePort);
	InitFonts();
	InitWindows();
	InitMenus();
	TEInit();
	InitDialogs(NULL);
	FlushEvents (everyEvent, 0);
	InitCursor();
#elif defined(WIN32)

  /* The code for Window support is a mixture of tutorials found on web
     and code provided by Joerg Anders. Basically, dont ask me too many
     questions about it :) */

  /* Open connection to display */  
  mavlib_dpy = GetModuleHandle(NULL);
  if (!mavlib_dpy) {
    fprintf(stderr, "Error: cannot connect to screen\n");
    exit(1);
  }

  /* Register class */
  wc.style= CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc= (WNDPROC) mavlib_winEventHandler;
  wc.cbClsExtra= 0;
  wc.cbWndExtra= 0;
  wc.hInstance= mavlib_dpy;
  wc.hIcon= 0;
  wc.hCursor= LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground= NULL;
  wc.lpszMenuName= NULL;
  wc.lpszClassName= "Maverik";
    
  if (!RegisterClass(&wc)) {
    fprintf(stderr, "Error: failed to register class\n");
    exit(1);
  }
#else
  /* Open connection to display */  
  mavlib_dpy= XOpenDisplay(NULL);

  if (!mavlib_dpy) {
    fprintf(stderr, "Error: cannot connect to X server %s\n", XDisplayName(NULL));
    exit(1);
  }
#endif

#ifndef MAV_SUNOS4
  /* clean up on application exit */
  atexit(mavlib_gfxExit);
#endif

#if !defined(WIN32) && !defined(macintosh)
  mavlib_scrnum= DefaultScreen(mavlib_dpy);
  mavlib_rootwin= RootWindow(mavlib_dpy, mavlib_scrnum);
#endif
#endif

#ifndef macintosh
  /* use environment variable to look for a Voodoo card */
  voodoo= getenv("MESA_GLX_FX");
  if (voodoo) {
    if (!strcmp(voodoo, "f")) mavlib_voodoo= 1;
    if (!strcmp(voodoo, "fullscreen")) mavlib_voodoo= 1;
  }
#endif

  return 1;
}



/* Routine to get the resolution of the display */

void mav_gfxWindowResGet(int *xres, int *yres)
{
#ifdef MAV_NONE
  *xres=1280;
  *yres=1024;
#else
#ifdef macintosh
  GDHandle gdev = GetMainDevice ();
  Rect bounds = (*gdev)->gdRect;
  *yres = bounds.bottom;
  *xres = bounds.right;
#elif defined(WIN32)
  *xres= GetSystemMetrics(SM_CXSCREEN);
  *yres= GetSystemMetrics(SM_CYSCREEN);
#else
  *xres= DisplayWidth(mavlib_dpy, mavlib_scrnum);
  *yres= DisplayHeight(mavlib_dpy, mavlib_scrnum);
#endif
#endif
}



/* Routine to set the current window */

void mav_gfxWindowSet(int i)
{
#ifndef MAV_NONE
#if defined(macintosh)
  aglSetDrawable (mavlib_winhand[i].ctx, (CGrafPort *)mavlib_winhand[i].win);
  aglSetCurrentContext (mavlib_winhand[i].ctx);
#elif defined(WIN32)
  wglMakeCurrent(mavlib_winhand[i].hdc, mavlib_winhand[i].ctx);
#else
#ifdef MAV_IRISGL
  GLXwinset(mavlib_dpy, mavlib_winhand[i].win);
#else
  glXMakeCurrent(mavlib_dpy, mavlib_winhand[i].win, mavlib_winhand[i].ctx);
#endif
#endif
  mavlib_currwin= i;
#endif
}



/* Routine to swap the buffers of the current window */

void mav_gfxWindowBuffersSwap(void)
{
#ifndef MAV_NONE
#if defined(macintosh)
  aglSwapBuffers (mavlib_winhand[mavlib_currwin].ctx);
#elif defined(WIN32)
  SwapBuffers(mavlib_winhand[mavlib_currwin].hdc);
#else
#ifdef MAV_IRISGL
  swapbuffers();
#else
  glXSwapBuffers(mavlib_dpy, mavlib_winhand[mavlib_currwin].win);
#endif
#endif
#endif
}



/* Routine to read a 2D raster font and store as a display list (OpenGL only) */

#ifdef MAV_OPENGL
GLuint mavlib_fontBase[MAX_FONTS];
#endif

int mav_gfxWindowFontSet(char *s, int i, int *width)
{
#ifdef MAV_OPENGL
#ifdef macintosh
 int j;
 mavlib_fontBase[i] = glGenLists((GLuint) 256);
 if (mavlib_fontBase[i] == 0) return -2;
 if (!aglUseFont (mavlib_winhand[mavlib_currwin].ctx, 4 /*monaco*/, 1 /*bold*/, 10, 0, 255, mavlib_fontBase[i])) {
 	return -1;
 }
  for (j=0; j<=255; j++) width[j]= 10;
#elif defined(WIN32)
  unsigned int first, last;

  first=0;
  last=255;

  if (strcmp(s, "-adobe-helvetica-bold-r-*-*-14-140-*-*-*-*-*-*")) {
    fprintf(stderr, "Warning: defining fonts not supported on Windows, using default\n");
  }

  mavlib_fontBase[i] = glGenLists((GLuint) last+1);
  if (mavlib_fontBase[i] == 0) return -2;

  wglUseFontBitmaps(mavlib_winhand[mavlib_currwin].hdc, first, last, mavlib_fontBase[i]+first);
  GetCharWidth32(mavlib_winhand[mavlib_currwin].hdc, first, last, width);
#else
  XFontStruct *fontInfo;
  Font id;
  unsigned int first, last;
  int j;

  fontInfo = XLoadQueryFont(mavlib_dpy, s);

  if (!fontInfo) return -1;

  id = fontInfo->fid;
  first = fontInfo->min_char_or_byte2;
  last = fontInfo->max_char_or_byte2;

  mavlib_fontBase[i] = glGenLists((GLuint) last+1);
  if (mavlib_fontBase[i] == 0) return -2;

  glXUseXFont(id, first, last-first+1, mavlib_fontBase[i]+first);

  for (j=first; j<=last; j++) width[j]= fontInfo->per_char[j-first].width;
#endif
#endif

  return 0;
}



/* Routine to display a string in a 2D raster font */ 

void mav_gfxWindowStringDisplay(char *s, int font)
{
#ifndef MAV_NONE
#ifdef MAV_IRISGL
  charstr(s);
#else
  glPushAttrib(GL_LIST_BIT);
  glListBase(mavlib_fontBase[font]);
  glCallLists(strlen(s), GL_UNSIGNED_BYTE, (GLubyte *)s);
  glPopAttrib();
#endif
#endif
}


#ifdef MAV_OPENGL
#ifdef WIN32
/* Routine to create a OpenGL rendering context under Windows */

HGLRC mavlib_winSetUpGL(HDC hdc)
{
  static PIXELFORMATDESCRIPTOR pfd = {
    sizeof(PIXELFORMATDESCRIPTOR),  // size of this pfd
    1,                              // version number
    PFD_DRAW_TO_WINDOW              // support window
    |  PFD_SUPPORT_OPENGL           // support OpenGL
    |  PFD_DOUBLEBUFFER,            // double buffered
    PFD_TYPE_RGBA,                  // RGBA type
    16,                             // 16-bit color depth
    0, 0, 0, 0, 0, 0,               // color bits ignored
    0,                              // no alpha buffer
    0,                              // shift bit ignored
    0,                              // no accumulation buffer
    0, 0, 0, 0,                     // accum bits ignored
    32,                             // 32-bit z-buffer      
    0,                              // no stencil buffer
    0,                              // no auxiliary buffer
    PFD_MAIN_PLANE,                 // main layer
    0,                              // reserved
    0, 0, 0                         // layer masks ignored
  };

  int pixelFormat;
  HGLRC rv = 0;

  pixelFormat= ChoosePixelFormat(hdc, &pfd);
  if (pixelFormat) {
    if (SetPixelFormat(hdc, pixelFormat, &pfd)) {
      rv= wglCreateContext(hdc);
      if (rv) {
	if (!wglMakeCurrent(hdc, rv)) {
	  wglDeleteContext(rv);
	  rv=0;
	}
      }
    }
  }

  return rv;
}

int mavlib_win32EventInfo[50]; /* Event info stored here */
int mavlib_win32EventGood=0;   /* Indicates type of event */
int mavlib_win32Create=-1;     /* Indicates id of window for create event */

/* This callback executed by DispatchMessage in mav_gfxWindowEventGet */

LONG WINAPI mavlib_winEventHandler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam) 
{
  LONG rv= 1;
  PAINTSTRUCT ps;
  int v1=-1, v2=-1;

  /* Set event indicator to zero - not a managed event */
  mavlib_win32EventGood=0;

  switch (umsg) {
  case WM_CREATE: /* Create Window event */
    if (mavlib_win32Create!=-1) 
    {
      mavlib_winhand[mavlib_win32Create].hdc= GetDC(hwnd);
      mavlib_winhand[mavlib_win32Create].ctx= mavlib_winSetUpGL(mavlib_winhand[mavlib_win32Create].hdc);

      if (!mavlib_winhand[mavlib_win32Create].ctx) {
	fprintf(stderr, "Error: failed to create context\n");
	exit(1);
      }
    }
    else
    {
      fprintf(stderr, "Error: unexpected create message\n");
      exit(1);
    }
    break;

  case WM_CLOSE: /* Pressed on close icon */
    exit(1);
    break;


  case WM_SYSKEYDOWN: /* Keyboard event - fill in info */
  case WM_KEYDOWN:
    if (v1==-1) v1=0;
  case WM_SYSKEYUP:
  case WM_KEYUP:
    if (v1==-1) v1=1;

    /* Bit 30 of lparam is set if key already held down */
    if (v1==0 && lparam & (1 << 30)) break;

    /* The return value of this event */
    mavlib_win32EventGood=1; 

    /* Get the id of the window in which the event occurred */
    mavlib_win32EventInfo[0]= mavlib_winlookup(hwnd);

    /* Get pointer position */
    mav_gfxWindowPointerGet(mavlib_win32EventInfo[0], &mavlib_win32EventInfo[1], &mavlib_win32EventInfo[2], &mavlib_win32EventInfo[3], &mavlib_win32EventInfo[4], NULL);
    
    /* Pressed or released */
    mavlib_win32EventInfo[5]=v1;

    /* Get modifier status */
    if (GetKeyState(VK_SHIFT)<0) /* Shift key up/down */ 
    {
      mavlib_win32EventInfo[7]= 1; /* Pressed (which is represented by 0 elsewhere!) */
    }
    else
    {
      mavlib_win32EventInfo[7]= 0; /* Released */
    }

    if (GetKeyState(VK_CONTROL)<0) /* Ctrl key up/down */ 
    {
      mavlib_win32EventInfo[8]= 1;
    }
    else
    {
      mavlib_win32EventInfo[8]= 0;
    }
    
    if (GetKeyState(VK_MENU)<0) /* Alt key up/down */ 
    {
      mavlib_win32EventInfo[9]= 1;
    }
    else
    {
      mavlib_win32EventInfo[9]= 0;
    }

    /* Translate keycode into ASCII value or #defines */
    mavlib_win32EventInfo[6]=0;
    switch (wparam) {
    case VK_F1: mavlib_win32EventInfo[6]= 300; break;
    case VK_F2: mavlib_win32EventInfo[6]= 301; break;
    case VK_F3: mavlib_win32EventInfo[6]= 302; break;
    case VK_F4: mavlib_win32EventInfo[6]= 303; break;
    case VK_F5: mavlib_win32EventInfo[6]= 304; break;
    case VK_F6: mavlib_win32EventInfo[6]= 305; break;
    case VK_F7: mavlib_win32EventInfo[6]= 306; break;
    case VK_F8: mavlib_win32EventInfo[6]= 307; break;
    case VK_F9: mavlib_win32EventInfo[6]= 308; break;
    case VK_F10: mavlib_win32EventInfo[6]= 309; break;
    case VK_F11: mavlib_win32EventInfo[6]= 310; break;
    case VK_F12: mavlib_win32EventInfo[6]= 311; break;
    case VK_UP: mavlib_win32EventInfo[6]= 312; break;
    case VK_DOWN: mavlib_win32EventInfo[6]= 313; break;
    case VK_LEFT: mavlib_win32EventInfo[6]= 314; break;
    case VK_RIGHT: mavlib_win32EventInfo[6]= 315; break;
    case VK_PRIOR: mavlib_win32EventInfo[6]= 316; break;
    case VK_NEXT: mavlib_win32EventInfo[6]= 317; break;
    case VK_SHIFT: mavlib_win32EventInfo[6]= 318; break;
    case VK_MENU: mavlib_win32EventInfo[6]= 320; break;
    case VK_HOME: mavlib_win32EventInfo[6]= 324; break;
    case VK_END: mavlib_win32EventInfo[6]= 325; break;
    case VK_INSERT: mavlib_win32EventInfo[6]= 326; break;
    case VK_CONTROL: mavlib_win32EventInfo[6]= 327; break;
    case VK_CAPITAL: mavlib_win32EventInfo[6]= 329; break;
    default: mavlib_win32EventInfo[6]= MapVirtualKey(wparam, 2); break;
    }

    /* Windows reports everything as uppercase - compensate for this */
    if (mavlib_win32EventInfo[6]>='A' && mavlib_win32EventInfo[6]<='Z' && !mavlib_win32EventInfo[7]) mavlib_win32EventInfo[6]+=32;

    /* TODO - do above for punctuation characters */

    /* No event if we cant translate keycode */
    if (mavlib_win32EventInfo[6]==0) mavlib_win32EventGood=0;

    /* End of event */
    mavlib_win32EventInfo[10]= -999;
    break;

  case WM_LBUTTONDOWN: /* Mouse button event - fill in info */
    if (v1==-1) v1=1;
    if (v2==-1) v2=0;
  case WM_MBUTTONDOWN:
    if (v1==-1) v1=2;
    if (v2==-1) v2=0;
  case WM_RBUTTONDOWN:
    if (v1==-1) v1=3;
    if (v2==-1) v2=0;
  case WM_LBUTTONUP:
    if (v1==-1) v1=1;
    if (v2==-1) v2=1;
  case WM_MBUTTONUP:
    if (v1==-1) v1=2;
    if (v2==-1) v2=1;
  case WM_RBUTTONUP:
    if (v1==-1) v1=3;
    if (v2==-1) v2=1;
    
    /* The return value of this event */
    mavlib_win32EventGood=2;

    /* Get the id of the window in which the event occurred */
    mavlib_win32EventInfo[0]= mavlib_winlookup(hwnd);

    /* Get pointer position */
    mav_gfxWindowPointerGet(mavlib_win32EventInfo[0], &mavlib_win32EventInfo[1], &mavlib_win32EventInfo[2], &mavlib_win32EventInfo[3], &mavlib_win32EventInfo[4], NULL);

    /* Pressed or released */
    mavlib_win32EventInfo[5]=v2;

    /* Which button */
    mavlib_win32EventInfo[6]=v1;

    /* Get modifier status */
    if (GetKeyState(VK_SHIFT)<0) /* Shift key up/down */ 
    {
      mavlib_win32EventInfo[7]= 1; /* Pressed (which is represented by 0 elsewhere!) */
    }
    else
    {
      mavlib_win32EventInfo[7]= 0; /* Released */
    }

    if (GetKeyState(VK_CONTROL)<0) /* Ctrl key up/down */ 
    {
      mavlib_win32EventInfo[8]= 1;
    }
    else
    {
      mavlib_win32EventInfo[8]= 0;
    }
    
    if (GetKeyState(VK_MENU)<0) /* Alt key up/down */ 
    {
      mavlib_win32EventInfo[9]= 1;
    }
    else
    {
      mavlib_win32EventInfo[9]= 0;
    }
    
    /* End of event */
    mavlib_win32EventInfo[10]=-999;
    break;

  case WM_SIZE:  /* Resize event - store in winhand for now */
    v1= mavlib_winlookup(hwnd);
    mavlib_winhand[v1].width= LOWORD(lparam);
    mavlib_winhand[v1].height= HIWORD(lparam);
    mavlib_winhand[v1].resized= 1;
    break;

    /* TODO - expose, enter/leave and mapping events */

  default: /* Let the system deal with all other events */
    rv= DefWindowProc(hwnd, umsg, wparam, lparam);
  }

  return rv;
}
#endif
#endif



/* Routine to open a window and a OpenGL/IrisGL context */

void mav_gfxWindowOpen(int id, int x, int y, int width, int height, char *nm, int wmplacement, int sb, int qb, int ms, int ab, int *wret, int *hret)
{
#ifdef MAV_NONE
  *wret= width;
  *hret= height;
#else
#ifdef WIN32

  mavlib_win32Create=id;
  mavlib_winhand[id].win= CreateWindow("Maverik", nm,
			 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW,
                         x, y, width, height,
                         NULL, NULL, mavlib_dpy, NULL);
  mavlib_win32Create=-1;

  mavlib_winhand[id].width=-1;
  mavlib_winhand[id].height=-1;
  mavlib_winhand[id].resized=0;
  
  if (!mavlib_winhand[id].win) {
    fprintf(stderr, "Error: Couldn't open window!\n");
    exit(1);
  }

  ShowWindow(mavlib_winhand[id].win, SW_SHOWDEFAULT);
  UpdateWindow(mavlib_winhand[id].win);
  SetFocus(mavlib_winhand[id].win);

  *wret= width;
  *hret= height;

#elif defined(macintosh)
  AGLDrawable win;
  AGLPixelFormat fmt;
  AGLContext ctx;
  Rect rect;
  Str255 title;
  GLint attrib[20];
  int i=0;
  for (i=19; i>=0; i--) {
  	attrib[i]=AGL_NONE;
  }
  i=0;
  attrib[i]=AGL_RGBA; i++;
  attrib[i]=AGL_MAXIMUM_POLICY; i++;
  if (!sb) {
  	attrib[i] = AGL_DOUBLEBUFFER; i++;
  }
  if (ab) {
  	attrib[i] = AGL_ACCUM_RED_SIZE; i++;
  	attrib[i] = 4; i++;
  	attrib[i] = AGL_ACCUM_GREEN_SIZE; i++;
  	attrib[i] = 4; i++;
  	attrib[i] = AGL_ACCUM_BLUE_SIZE; i++;
  	attrib[i] = 4; i++;
  	/*attrib[i] = AGL_ACCUM_ALPHA_SIZE; i++;
  	attrib[i] = 4; i++;*/
  }
  attrib[i] = AGL_DEPTH_SIZE; i++;
  attrib[i] = 16; i++;
  attrib[i] = AGL_NONE;
  
  strncpy ((char*)title+1, nm, 255);
  title[0] = strlen (nm);
  
  SetRect (&rect, x, y, width+x, height+y);
  win = (AGLDrawable) NewCWindow (0L, &rect, title, false, documentProc, (WindowPtr) -1L, false, 0L);
  if (!win) {
  	fprintf (stderr, "could not open window\n");
  	return;
  }
  ShowWindow ((GrafPort*) win);
  HiliteWindow ((GrafPort*) win, true);
  SetPort ((GrafPort*) win);
  fmt = aglChoosePixelFormat (NULL, 0, attrib);
  ctx = aglCreateContext (fmt, NULL);
  aglSetDrawable (ctx, win);
  aglSetCurrentContext (ctx);
  mavlib_winhand[id].win = (GrafPort*)win;
  mavlib_winhand[id].ctx = ctx;

  *wret = width; *hret = height;
#else
  XVisualInfo *visinfo=NULL;
  Colormap cmap;
  XSetWindowAttributes attr;
  XWindowAttributes winattr;
  XTextProperty tp;
  XSizeHints sh;
  XClassHint ch;
  XEvent e;
  int attr_flags;

/* Get an RGBA double buffered visual */

#ifdef MAV_IRISGL
  GLXconfig params[3] = {{GLX_NORMAL, GLX_RGB, TRUE}, {GLX_NORMAL, GLX_DOUBLE, TRUE}, {0, 0, 0}};
  GLXconfig *next, *retconfig;
  XVisualInfo template;
  int nret;

  if (sb) params[1].arg=FALSE;

  if ((retconfig = GLXgetconfig(mavlib_dpy, mavlib_scrnum, params)) == NULL) {
    fprintf(stderr, "Error: couldn't get an RGBA, Double-buffered visual\n");
    exit(1);
  }

  /*
   * Scan through config info, pulling info needed to create a window
   * that supports the rendering mode.
   */

  for (next = retconfig; next->buffer; next++) {
    if (next->buffer == GLX_NORMAL) {
      if (next->mode == GLX_COLORMAP) {
        cmap = next->arg;
      }
      else if (next->mode == GLX_VISUAL) {
        template.visualid = next->arg;
        template.screen = DefaultScreen(mavlib_dpy);
        visinfo = XGetVisualInfo(mavlib_dpy, VisualScreenMask | VisualIDMask, &template, &nret);
      }
    }
  }

#else

  int attrib[50];
  int ac=9;

  attrib[0]= GLX_RGBA;
  attrib[1]= GLX_RED_SIZE;
  attrib[2]= 1;
  attrib[3]= GLX_GREEN_SIZE;
  attrib[4]= 1;
  attrib[5]= GLX_BLUE_SIZE;
  attrib[6]= 1;
  attrib[7]= GLX_DEPTH_SIZE;
  attrib[8]= 1;
  
  if (!sb) {
    attrib[ac]= GLX_DOUBLEBUFFER;
    ac++;
  }

  if (ab) {
    attrib[ac]= GLX_ACCUM_RED_SIZE;
    ac++;
    attrib[ac]= 1;
    ac++;
    attrib[ac]= GLX_ACCUM_GREEN_SIZE;
    ac++;
    attrib[ac]= 1;
    ac++;
    attrib[ac]= GLX_ACCUM_BLUE_SIZE;
    ac++;
    attrib[ac]= 1;
    ac++;
  }
  
#ifdef GL_SGIS_multisample
  if (ms) {
    attrib[ac]= GLX_SAMPLES_SGIS;
    ac++;
    attrib[ac]= 4;
    ac++;
  }
#endif

  attrib[ac]= None;

  visinfo= glXChooseVisual(mavlib_dpy, mavlib_scrnum, attrib);
  if (!visinfo) {
    fprintf(stderr, "Error: couldn't get an RGBA");
    if (!sb) fprintf(stderr, ", double-buffered");
    if (ms) fprintf(stderr, ", multi-sampled");
    if (ab) fprintf(stderr, ", acculmation-buffered");
    fprintf (stderr, " visual\n");
    exit(1);
  }

#endif

  cmap=XCreateColormap(mavlib_dpy, mavlib_rootwin, visinfo->visual, AllocNone);

  /* set window attributes */
  attr.colormap=cmap;
  attr.event_mask= ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask;
  attr.border_pixel=BlackPixel(mavlib_dpy, mavlib_scrnum);
  attr.background_pixel=BlackPixel(mavlib_dpy, mavlib_scrnum );
  attr_flags = CWColormap | CWEventMask | CWBorderPixel | CWBackPixel;

   /* Create the window */
  mavlib_winhand[id].win = XCreateWindow(mavlib_dpy, mavlib_rootwin, x,y, width, height, 0, visinfo->depth, InputOutput, visinfo->visual, attr_flags, &attr);

  if (!mavlib_winhand[id].win) {
    fprintf(stderr, "Error: Couldn't open window!\n");
    exit(1);
  }
  
  /* Set its name and resource class */
  ch.res_name= NULL;
  ch.res_class= "MaverikApp";

  XStringListToTextProperty(&nm, 1, &tp);
  XSetWMProperties(mavlib_dpy,  mavlib_winhand[id].win, &tp, &tp, 0, 0, 0, 0, &ch);

  /* Reposition window to requested position (window manager may not comply) */
  if (!wmplacement) {
    sh.flags = USPosition | USSize;
    XSetWMProperties(mavlib_dpy,  mavlib_winhand[id].win, 0, 0, 0, 0, &sh, 0, 0);
  }
  
  /* map window and wait notify event - i.e. its now visible  */
  XMapWindow(mavlib_dpy, mavlib_winhand[id].win);

  do {
    XNextEvent(mavlib_dpy, &e);
  } while (e.type!=MapNotify || e.xmap.window!=mavlib_winhand[id].win);

  
  /* get actual width and height of window (again pesky window managers) */
  XGetWindowAttributes(mavlib_dpy, mavlib_winhand[id].win, &winattr);
  *wret= winattr.width;
  *hret= winattr.height;
  
  /* create graphics context */

#ifdef MAV_IRISGL
  /*
   * Rescan configuration info and find window slot that getconfig
   * provided.  Fill it in with the window we just created.
   */
  for (next = retconfig; next->buffer; next++) {
    if ((next->buffer == GLX_NORMAL) && (next->mode == GLX_WINDOW)) {
      next->arg = mavlib_winhand[id].win;
      break;
    }
  }

  if (GLXlink(mavlib_dpy, retconfig) < 0) {
    fprintf(stderr, "Error: could not link with the GL\n");
    exit(1);
  }  

#else
  if (id==1 || !mav_opt_shareContexts)
  {
    mavlib_winhand[id].ctx= glXCreateContext(mavlib_dpy, visinfo, NULL, True);
  }
  else
  {
    mavlib_winhand[id].ctx= glXCreateContext(mavlib_dpy, visinfo, mavlib_winhand[1].ctx, True);
  }

  if (!mavlib_winhand[id].ctx) {
    fprintf(stderr, "Error: failed to create context\n");
    exit(1);
  }
#endif
#endif
  
  /* Set to active window */
  mav_gfxWindowSet(id);

#ifdef MAV_IRISGL
  {
    /* define texturing  environment for IrisGL */
    float tevprops1[]= {TV_DECAL, TV_NULL};
    float tevprops2[]= {TV_MODULATE, TV_NULL};
    tevdef(1, 0, tevprops1);
    tevdef(2, 0, tevprops2);

    /* we'll have a bit of sub pixel accuracy */
    subpixel(TRUE);
  }
#endif

  if (id==1 && mav_opt_bindTextures) {
#ifdef MAV_SUNOS4
    fprintf(stderr, "Warning: bind texture extension not available on SunOS4, ignoring.\n");
#else
#ifdef GL_EXT_texture_object
    mavlib_bindTextureIndex= malloc(mav_opt_maxTextures*3*sizeof(GLuint));
    if (!mavlib_bindTextureIndex) fprintf(stderr, "Warning: bind texture malloc failed, ignoring.\n");
    glGenTexturesEXT(mav_opt_maxTextures*3, mavlib_bindTextureIndex);
#else
    fprintf(stderr, "Warning: no bind texture extension, ignoring.\n");
#endif
#endif
  }
#endif
}



/* Routine to close a window */

void mav_gfxWindowClose(int id)
{
#ifndef MAV_NONE
#if defined(macintosh)
  if (mavlib_winhand[id].win) {
     aglSetCurrentContext(NULL);
     aglSetDrawable(mavlib_winhand[id].ctx, NULL);
     aglDestroyContext(mavlib_winhand[id].ctx);
     DisposeWindow(mavlib_winhand[id].win);
  }
#elif defined(WIN32)
  wglDeleteContext(mavlib_winhand[id].ctx);
  DestroyWindow(mavlib_winhand[id].win);
  mavlib_winhand[id].win= (HWND) NULL;
#else
  XDestroyWindow(mavlib_dpy, mavlib_winhand[id].win);
  mavlib_winhand[id].win= (Window) NULL;
#endif
#endif
}



/* 
   Check if any events are outstanding (do not block if there are not) 
   Return value gives the type of event.
*/

int mav_gfxWindowEventPeek(void)
{
  int rv=0;

#ifndef MAV_NONE
#if defined(macintosh)
  EventRecord event;
  if (EventAvail (everyEvent, &event)) {
    switch (event.what) {
      case mouseDown:
      case mouseUp:
        rv=2;
        break;
      case autoKey:
      case keyDown:
      case keyUp:
        rv=1;
        break;
      case updateEvt:
        rv=6;
        break;
      case activateEvt:
        rv=5;
        break;
      case kHighLevelEvent:
      default:
        printf("unknown event %d\n", event.what);
        rv=-1;
        break;
    }
  }
#elif defined(WIN32)
  /* TODO - peek event, is this needed? */
#else
  XEvent event;

  if (XEventsQueued(mavlib_dpy, QueuedAfterReading)) {

/* Look at, but dont remove, the next event */

    XPeekEvent(mavlib_dpy, &event);

    switch(event.type) {
    case KeyPress:
    case KeyRelease:
      rv=1;
      break;
    case ButtonPress:
    case ButtonRelease:
      rv=2;
      break;
    case ConfigureNotify:
      rv=3;
      break;
    case MapNotify:
    case UnmapNotify:
      rv=4;
      break;
    case EnterNotify:
    case LeaveNotify:
      rv=5;
      break;
    case Expose:
      rv=6;
      break;
    default:
      printf("unknown event %i\n", event.type);
      rv=-1;
      break;
    }
  }
#endif
#endif

  return rv;
}


#ifndef MAV_NONE
#ifndef WIN32
void mavlib_eventDump(int i, int w)
{
  printf("Window %i - ", w);

#if defined(macintosh)
  printf("Event %d\n", i);
#else
  switch(i) {

  case KeyPress:
    printf("Key Press\n");
    break;
    
  case KeyRelease:
    printf("Key Release\n");
    break;

  case ButtonPress:
    printf("Button Press\n");
    break;

  case ButtonRelease:
    printf("Button Release\n");
    break;

  case ConfigureNotify:
    printf("Configure Notify\n");
    break;
    
  case MapNotify:
    printf("Map Notify\n");
    break;

  case UnmapNotify:
    printf("UnMap Notify\n");
    break;

  case EnterNotify: 
    printf("Enter Notify\n");
    break;

  case LeaveNotify:
    printf("Leave Notify\n");
    break;

  case Expose:
    printf("Expose\n");
    break;
    
  default:
    printf("Unknown event %i\n", i);
    break;
  }
#endif
  printf("\n");
}
#endif
#endif

/* 
   Get next event returning data in info array (again, do not block if there are no event) 
   Return value gives the type of event.
*/

#ifndef MAV_NONE
#if !defined(WIN32) && !defined(macintosh)
int (*mavlib_extraXEventHandler)(XEvent)= NULL;
#endif
#endif

#ifdef macintosh
int mavlib_macLastEvent[20];
#endif

int mav_gfxWindowEventGet(int *info)
{
  int rv=0;

#ifndef MAV_NONE
#if defined(macintosh)
  EventRecord event;
  
  if (WaitNextEvent (everyEvent, &event, 100, nil)) {
    /* first check if the last event was a key press. if so, resend a key release event first. */
    if (mavlib_macLastEvent[11] == 1 && event.what != autoKey) {
       mavlib_macLastEvent[5]=1; /* set to key release */
       mavlib_macLastEvent[11] = 0;
       mavlib_dealWithKeyboardEvent(mavlib_macLastEvent);
       mavlib_macLastEvent[11]=0; /* reset */
    }
    switch (event.what) {
      case mouseDown:
      case mouseUp: {
 	    int onwhat;
		WindowPtr win;
		  
        info[0]= mavlib_winlookup(FrontWindow ());
		onwhat = FindWindow (event.where, &win);
		/*if (!win) return rv;*/
		switch (onwhat) { /* test for window handling */
		    case inSysWindow:
			   SystemClick(&event, win);/* pass clicks to Desk Accessories */
			   return rv;
		    case inMenuBar: {
		       short menuID, menuEntry;
		       long choosen = MenuSelect (event.where);
		       menuID = (choosen>>16)&0xffff;
		       menuEntry = choosen&0xffff;
		       if (menuID > 0) {
		         Str255	DAName;
		         GetMenuItemText (GetMenuHandle (menuID), menuEntry, DAName);
		         OpenDeskAcc (DAName);
		       }
		       HiliteMenu (0);
		       return rv;
		    }
		    case inContent:
		       if (info[0] != mavlib_winlookup (win)) {
		          SelectWindow (win);
		          return rv;
		       }
 	           break;
		    case inDrag:
		       if (info[0] != mavlib_winlookup (win)) {
		          SelectWindow (win);
		          return rv;
		       }
		       if (info[0]>0) DragWindow (win, event.where, &(*GetGrayRgn())->rgnBBox); return rv;
		       break;
		    case inGrow:
			   if (info[0]>0) {
			      long newsize;
			      RgnHandle region;
			      newsize = GrowWindow (win, event.where, &(*GetGrayRgn())->rgnBBox);
			      info[1] = newsize&0xffff;
			      info[2] = (newsize>>16) & 0xffff;
			      SizeWindow (win, info[1], info[2], true);
			      aglUpdateContext (mavlib_winhand[info[0]].ctx);
			      mavlib_dealWithResizeEvent (info);
			      region = ((WindowPeek)win)->strucRgn;
			      InvalRgn (region);
			      return 0; /* must update */
			   }
			case inGoAway:
			   if (info[0]>0) mav_windowDelete (info[0]); return rv;
		} /* switch onwhat */

	    info[1]= event.where.h - ((info[0]<=0)?0:
	    		(*(((WindowPeek)mavlib_winhand[info[0]].win)->contRgn))->rgnBBox.left);
	    info[2]= event.where.v - ((info[0]<=0)?0:
	    		(*(((WindowPeek)mavlib_winhand[info[0]].win)->contRgn))->rgnBBox.top);
	    info[3]= event.where.h;
	    info[4]= event.where.v;
	
	    if (event.what==mouseDown) info[5]=0;
	    if (event.what==mouseUp) info[5]=1;
	
		/*printf ("button pos x:%i y:%i rootx:%i rooty:%i\n", info[1],info[2],info[3],info[4]);*/
	/* set mouse button number */
	    if (event.modifiers & controlKey) {
	      info[6]=2; /* middle button when control held */
	    } else if (event.modifiers & optionKey) {
	      info[6]=3; /* right button when alt held */
	    } else {
	      info[6]=1; /* left button */
	    }  
        info[7]=event.modifiers & shiftKey; /* shift modifier */
        info[8]=event.modifiers & controlKey; /* control modifier */
        info[9]=event.modifiers & optionKey; /* alt modifier */
        rv=2;
        break;
      }
      case autoKey:
      /*case keyUp :*/ /* keyUp events are not always sent to the queue !!! */
      case keyDown: {
        char theKey = (event.message & keyCodeMask) >> 8;
        int theChar = event.message & charCodeMask;
        info[0]= mavlib_winlookup(FrontWindow ());
	    info[1]= event.where.h - ((info[0]<=0)?0:
	    		(*(((WindowPeek)mavlib_winhand[info[0]].win)->contRgn))->rgnBBox.left); /* should be root win */
	    info[2]= event.where.v - ((info[0]<=0)?0:
	    		(*(((WindowPeek)mavlib_winhand[info[0]].win)->contRgn))->rgnBBox.top); /* should be root win */
	    info[3]= event.where.h;
	    info[4]= event.where.v;
	
	    if (event.what==keyDown || event.what==autoKey) {
	        info[5]=0;
	    }
	    if (event.what==keyUp) {
	    	info[5]=1;
	    }
	    /*printf ("key code is %hi  the char is %i or %c\n", theKey, theChar, theChar);*/
	    
		switch (theKey) {
			case 0x7a: theChar = 300; break; /* XK_F1 */
			case 0x78: theChar = 301; break; /* XK_F2 */
			case 0x63: theChar = 302; break; /* XK_F4 */
			case 0x76: theChar = 303; break; /* XK_F5 */
			case 0x60: theChar = 304; break; /* XK_F5 */
			case 0x61: theChar = 305; break; /* XK_F6 */
			case 0x62: theChar = 306; break; /* XK_F7 */
			case 0x64: theChar = 307; break; /* XK_F8 */
			case 0x65: theChar = 308; break; /* XK_F9 */
			case 0x6d: theChar = 309; break; /* XK_F10 */
			case 0x67: theChar = 310; break; /* XK_F11 */
			case 0x6f: theChar = 311; break; /* XK_F12 */
			case 0x7e: theChar = 312; break; /* XK_Up */
			case 0x7d: theChar = 313; break; /* XK_Down */
			case 0x7b: theChar = 314; break; /* XK_Left */
			case 0x7c: theChar = 315; break; /* XK_Right */
			case 0x74: theChar = 316; break; /* XK_Page_Up */
			case 0x79: theChar = 317; break; /* XK_Page_Down */
			case 0x38: theChar = 318; break; /* XK_Shift_L */
			case 0x3c: theChar = 319; break; /* XK_Shift_R */
			case 0x3a: theChar = 320; break; /* XK_Alt_L */
			case 0x3d: theChar = 320; break; /* XK_Alt_R */
			case 0x37: theChar = 322; break; /* XK_Meta_L  == Apple Key */
			/* cannot distinguish the meta right from left on the Mac !! */
			case 0x73: theChar = 324; break; /* XK_Home */
			case 0x77: theChar = 325; break; /* XK_End */
			case 0x72: theChar = 326; break; /* XK_Insert */
			case 0x3b: theChar = 327; break; /* XK_Control_L */
			case 0x3e: theChar = 328; break; /* XK_Control_R */
			case 0x39: theChar = 329; break; /* XK_Caps_Lock */
			default: theKey = 0; break;
        }
        info[6]=theChar;
        info[7]=event.modifiers & shiftKey; /* shift modifier */
        info[8]=event.modifiers & controlKey; /* control modifier */
        info[9]=event.modifiers & optionKey; /* alt modifier */
        { int j;
          for (j=0; j<20; j++) { /* keep a copy */
            mavlib_macLastEvent[j] = info[j];
          }
          mavlib_macLastEvent[11] = 1; /* save this event identifier */
        }

        rv=1;
        break;
      }
      case updateEvt:
        info[0]= mavlib_winlookup((GrafPort*)event.message);
		info[1]=0;
        rv=6;
        break;
      case activateEvt:
        info[0]= mavlib_winlookup((GrafPort*)event.message);
        if (event.modifiers & activeFlag) {
          info[1]=1;
        } else {
          info[1]=0;
        }
        rv=5;
        break;
       case diskEvt:
	    if (event.message < 0) {
	       Point dialogpt = {100, 100};
		   DIBadMount(dialogpt, event.message);
	    }
	    break;
      case kHighLevelEvent:
      default:
        printf("unknown event %i\n", event.what);
        rv=-1;
        break;
    }
  	/*printf ("event is %i on %i\n", rv, info[0]);*/
    if (info[0]==-1) rv=-1; /* suppress events for others */
  }
#elif defined(WIN32)
  MSG msg;
  int i=0;

  /* Look for resize events */
  for (i=0; i<MAX_WINS; i++) {
    if (mavlib_winhand[i].win && mavlib_winhand[i].resized) {
      info[0]= i;
      info[1]= mavlib_winhand[i].width;
      info[2]= mavlib_winhand[i].height;
      mavlib_winhand[i].resized=0;
      return 3; /* Indicates a resize event */
    }
  }

  /* Get next event - non blocking */
  if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {	

    /* Deal with event - this calls the mavlib_winEventHandler callback fn */
    TranslateMessage(&msg);
    DispatchMessage(&msg);
      
    /* Is this an event dealt with my Maverik - value set by callback fn */
    if (mavlib_win32EventGood) {

      /* TODO - msg has a better pointer position info */

      /* Copy values filled in by callback fn into info */
      i=0;
      while (mavlib_win32EventInfo[i]!=-999) {
	info[i]=mavlib_win32EventInfo[i];
	i++;
	rv=mavlib_win32EventGood;
      }
    }
  }
#else
  XEvent event;
  KeySym ks;
  char tmp;

  if (XEventsQueued(mavlib_dpy, QueuedAfterReading)) {

/* Get next event - N.B. this is a blocking call */
      
    XNextEvent(mavlib_dpy, &event);

    /* get the id of the window in which the event occurred */
    info[0]= mavlib_winlookup(event.xany.window);

    /* only consider events for active Maverik windows */
    if (info[0]!=-1) {

      switch(event.type) {

      case KeyPress:
      case KeyRelease:
	rv=1;
	
	info[1]= event.xkey.x;
	info[2]= event.xkey.y;
	info[3]= event.xkey.x_root;
	info[4]= event.xkey.y_root;
	
	if (event.type==KeyPress) info[5]=0;
	if (event.type==KeyRelease) info[5]=1;
	
	/* Convert key to ASCII or symbolic value */
	
	info[6]=0;
	
	if (XLookupString(&event.xkey, &tmp, sizeof(tmp), &ks, NULL)) 
	{
	  info[6]= (int) tmp;
	}
	else
	{
	  switch (ks) {
	  case XK_F1: info[6]= 300; break;
	  case XK_F2: info[6]= 301; break;
	  case XK_F3: info[6]= 302; break;
	  case XK_F4: info[6]= 303; break;
	  case XK_F5: info[6]= 304; break;
	  case XK_F6: info[6]= 305; break;
	  case XK_F7: info[6]= 306; break;
	  case XK_F8: info[6]= 307; break;
	  case XK_F9: info[6]= 308; break;
	  case XK_F10: info[6]= 309; break;
	  case XK_F11: info[6]= 310; break;
	  case XK_F12: info[6]= 311; break;
	  case XK_Up: info[6]= 312; break;
	  case XK_Down: info[6]= 313; break;
	  case XK_Left: info[6]= 314; break;
	  case XK_Right: info[6]= 315; break;
#ifndef MAV_SUNOS4
	  case XK_Page_Up: info[6]= 316; break;
	  case XK_Page_Down: info[6]= 317; break;
#endif
	  case XK_Shift_L: info[6]= 318; break;
	  case XK_Shift_R: info[6]= 319; break;
	  case XK_Alt_L: info[6]= 320; break;
	  case XK_Alt_R: info[6]= 321; break;
	  case XK_Meta_L: info[6]= 322; break;
	  case XK_Meta_R: info[6]= 323; break;
	  case XK_Home: info[6]= 324; break;
	  case XK_End: info[6]= 325; break;
	  case XK_Insert: info[6]= 326; break;
	  case XK_Control_L: info[6]= 327; break;
	  case XK_Control_R: info[6]= 328; break;
	  case XK_Caps_Lock: info[6]= 329; break;
	  }
	}

	if (info[6]==0) rv=0;

	if (event.xkey.state&0x1)  /* Shift key up/down */ 
	{
	  info[7]= 1; /* Pressed (which is represented by 0 elsewhere!) */
	}
	else
	{
	  info[7]= 0; /* Released */
	}

	if ((event.xkey.state>>2)&0x1)  /* Ctrl key up/down */ 
	{
	  info[8]= 1;
	}
	else
	{
	  info[8]= 0;
	}

	if ((event.xkey.state>>3)&0x1)  /* Alt key up/down */ 
	{
	  info[9]= 1;
	}
	else
	{
	  info[9]= 0;
	}
	break;

      case ButtonPress:
      case ButtonRelease:
	rv=2;

	info[1]= event.xbutton.x;
	info[2]= event.xbutton.y;
	info[3]= event.xbutton.x_root;
	info[4]= event.xbutton.y_root;
	
	if (event.type==ButtonPress) info[5]=0;
	if (event.type==ButtonRelease) info[5]=1;
	info[6]= event.xbutton.button;

	if (event.xkey.state&0x1)  /* Shift key up/down */ 
	{
	  info[7]= 1; /* Pressed (which is represented by 0 elsewhere!) */
	}
	else
	{
	  info[7]= 0; /* Released */
	}
	
	if ((event.xkey.state>>2)&0x1)  /* Ctrl key up/down */ 
	{
	  info[8]= 1;
	}
	else
	{
	  info[8]= 0;
	}

	if ((event.xkey.state>>3)&0x1)  /* Alt key up/down */ 
	{
	  info[9]= 1;
	}
	else
	{
	  info[9]= 0;
	}
	break;

      case ConfigureNotify:
	rv=3;
	info[1]=event.xconfigure.width;
	info[2]=event.xconfigure.height;
	break;

      case MapNotify:
      case UnmapNotify:
	rv=4;
	if (event.type==MapNotify) info[1]=0;
	if (event.type==UnmapNotify) info[1]=1;
	break;

      case EnterNotify: 
	rv=5;
	/* turn off keyboard auto repeat when entering a Maverik window */
	XAutoRepeatOff(mavlib_dpy); 
	info[1]=0;
	break;

      case LeaveNotify:
	rv=5;
	/* turn on keyboard auto repeat when leaving a Maverik window */
	XAutoRepeatOn(mavlib_dpy);
	info[1]=1;
	break;

      case Expose:
	rv=6;
	break;

      default:
	if (mavlib_extraXEventHandler) 
	{
	  rv= (*mavlib_extraXEventHandler)(event);
	}
	else
	{
	  rv=-1;
	  fprintf(stderr, "unknown event %i\n", event.type);
	}
      }
    }
  }
#endif
#endif

  return rv;
}



/* Routine to return the position of the mouse in a window and root coords */

int mav_gfxWindowPointerGet(int win, int *x, int *y, int *rx, int *ry, int *buts)
{
  int rv=1;

#ifdef MAV_NONE
  *x=10;
  *y=20;
  *rx=30;
  *ry=40;
#else
#ifdef WIN32
  POINT point;

  if (win>0 && win<MAX_WINS && mavlib_winhand[win].win) 
  {
    if (GetCursorPos(&point)==0) {
      fprintf(stderr, "Error: failed to get cursor pos\n");
      exit(1);
    }

    /* Store root cords */
    *rx= point.x;
    *ry= point.y;
  
    /* Get in coords of specified window */
    if (ScreenToClient(mavlib_winhand[win].win, &point)==0) {
      fprintf(stderr, "Error: failed to convert cursor pos\n");
      exit(1);
    }

    /* Store window cords */
    *x= point.x;
    *y= point.y;
  }
  else
  {
    rv=0;
  }
#elif defined(macintosh)
  Point pt;
  RgnPtr rgn;
  GetMouse (&pt); /* get it in local coords */
  if (win > 0) {
	  rgn = *((WindowPeek)(mavlib_winhand[win].win))->strucRgn;
	  *x = pt.h; *y = pt.v;
	  *rx = pt.h+rgn->rgnBBox.left;
	  *ry = pt.v+rgn->rgnBBox.top;
      rv = 1;
  } else {
      rv = 0;
  }
#else
  Window dumroot, dumchild;
  unsigned int btnmask;

  if (win>0 && win<MAX_WINS && mavlib_winhand[win].win) 
  {
    XQueryPointer(mavlib_dpy, mavlib_winhand[win].win, &dumroot, &dumchild, rx, ry, x, y, &btnmask);

    if (buts) {
      buts[0]= !((btnmask>>8) & 0x1); /* left */
      buts[1]= !((btnmask>>9) & 0x1); /* middle */
      buts[2]= !((btnmask>>10) & 0x1); /* right */
    }
  }
  else
  {
    rv=0;
  }
#endif
#endif

  return rv;
}



/* Routine to set the mouses position */

void mav_gfxWindowPointerSet(int win, int x, int y)
{
#ifndef MAV_NONE
#ifdef WIN32
  POINT point;
  
  /* Point in coords of specified window */
  point.x= x;
  point.y= y;

  /* Get in coords of root window */
  if (ClientToScreen(mavlib_winhand[win].win, &point)==0) {
    fprintf(stderr, "Error: failed to convert cursor pos\n");
    exit(1);
  }

  /* Set cursor pos */
  SetCursorPos(point.x, point.y);
#elif defined(macintosh)
  printf ("cannot set mouse pointer \n");
#else
  XWarpPointer(mavlib_dpy, None, mavlib_winhand[win].win, 0,0,0,0, x, y);
#endif
#endif
}



/* Routine to return the state of a key */

int mav_gfxWindowKeyGet(int key)
{
#ifdef MAV_NONE
  return 1;
#else
#ifdef WIN32
  int vk;

  /* Convert to keycode */
  switch (key) {
  case 300: vk= VK_F1; break;
  case 301: vk= VK_F2; break;
  case 302: vk= VK_F3; break;
  case 303: vk= VK_F4; break;
  case 304: vk= VK_F5; break;
  case 305: vk= VK_F6; break;
  case 306: vk= VK_F7; break;
  case 307: vk= VK_F8; break;
  case 308: vk= VK_F9; break;
  case 309: vk= VK_F10; break;
  case 310: vk= VK_F11; break;
  case 311: vk= VK_F12; break;
  case 312: vk= VK_UP; break;
  case 313: vk= VK_DOWN; break;
  case 314: vk= VK_LEFT; break;
  case 315: vk= VK_RIGHT; break;
  case 316: vk= VK_PRIOR; break;
  case 317: vk= VK_NEXT; break;
  case 318: vk= VK_SHIFT; break;
  case 319: vk= VK_SHIFT; break;
  case 320: vk= VK_MENU; break;
  case 321: vk= VK_MENU; break;
  case 324: vk= VK_HOME; break;
  case 325: vk= VK_END; break;
  case 326: vk= VK_INSERT; break;
  case 327: vk= VK_CONTROL; break;
  case 328: vk= VK_CONTROL; break;
  case 329: vk= VK_CAPITAL; break;
  default: vk= key; break;
  }

  /* Get key state */
  if (GetKeyState(vk)<0)
  {
    return 0; /* Pressed */
  }
  else
  {
    return 1; /* Released */
  }
#elif defined(macintosh)
  unsigned int whatbyte;
  unsigned char bitmask;
  unsigned char theChar=0;
  unsigned char keys[16];
  GetKeys ((long*)keys);
  switch (key) {
		case 300: theChar =  0x7a; break; /* XK_F1 */
		case 301: theChar = 0x78; break; /* XK_F2 */
		case 302: theChar = 0x63; break; /* XK_F4 */
		case 303: theChar = 0x76; break; /* XK_F5 */
		case 304: theChar = 0x60; break; /* XK_F5 */
		case 305: theChar = 0x61; break; /* XK_F6 */
		case 306: theChar = 0x62; break; /* XK_F7 */
		case 307: theChar = 0x64; break; /* XK_F8 */
		case 308: theChar = 0x65; break; /* XK_F9 */
		case 309: theChar = 0x6d; break; /* XK_F10 */
		case 310: theChar = 0x67; break; /* XK_F11 */
		case 311: theChar = 0x6f; break; /* XK_F12 */
		case 312: theChar = 0x7e; break; /* XK_Up */
		case 313: theChar = 0x7d; break; /* XK_Down */
		case 314: theChar = 0x7b; break; /* XK_Left */
		case 315: theChar = 0x7c; break; /* XK_Right */
		case 316: theChar = 0x74; break; /* XK_Page_Up */
		case 317: theChar = 0x79; break; /* XK_Page_Down */
		case 318: theChar = 0x38; break; /* XK_Shift_L */
		case 319: theChar = 0x3c; break; /* XK_Shift_R */
		case 320: theChar = 0x3a; break; /* XK_Alt_L */
		case 321: theChar = 0x3d; break; /* XK_Alt_R */
		case 322:
		case 323: theChar = 0x37; break; /* XK_Meta_L  == Apple Key */
		case 324: theChar = 0x73; break; /* XK_Home */
		case 325: theChar = 0x77; break; /* XK_End */
		case 326: theChar = 0x72; break; /* XK_Insert */
		case 327: theChar = 0x3b; break; /* XK_Control_L */
		case 328: theChar = 0x3e; break; /* XK_Control_R */
		case 329: theChar = 0x39; break; /* XK_Caps_Lock */
		default: theChar = 0; break;
  }
  if (theChar>0) {
     whatbyte = (int)(theChar/8.0);
     bitmask = 1<<(theChar%8);
  /* a special key */
     return (keys[whatbyte] & bitmask)!=bitmask;
  } else {
     whatbyte = (int)(key/8.0);
     bitmask = 1<<(key%8);
  /* 7 bit ascii char */
     return (keys[whatbyte] & bitmask)!=bitmask;
  }
#else
  char rv[32], ip[2];
  int keysym=-1, keycode, c, r;

  /* Convert ASCII key or symbolic value to keysym */ 
  if (key>0 && key<255) 
  {
    ip[0]=key;
    ip[1]=0;
    keysym=XStringToKeysym(ip);
  }
  else
  {
    switch (key) {
    case 300: keysym=XK_F1; break;
    case 301: keysym=XK_F2; break;
    case 302: keysym=XK_F3; break;
    case 303: keysym=XK_F4; break;
    case 304: keysym=XK_F5; break;
    case 305: keysym=XK_F6; break;
    case 306: keysym=XK_F7; break;
    case 307: keysym=XK_F8; break;
    case 308: keysym=XK_F9; break;
    case 309: keysym=XK_F10; break;
    case 310: keysym=XK_F11; break;
    case 311: keysym=XK_F12; break;
    case 312: keysym=XK_Up; break;
    case 313: keysym=XK_Down; break;
    case 314: keysym=XK_Left; break;
    case 315: keysym=XK_Right; break;
#ifndef MAV_SUNOS4
    case 316: keysym=XK_Page_Up; break;
    case 317: keysym=XK_Page_Down; break;
#endif
    case 318: keysym=XK_Shift_L; break;
    case 319: keysym=XK_Shift_R; break;
    case 320: keysym=XK_Alt_L; break;
    case 321: keysym=XK_Alt_R; break;
    case 322: keysym=XK_Meta_L; break;
    case 323: keysym=XK_Meta_R; break;
    case 324: keysym=XK_Home; break;
    case 325: keysym=XK_End; break;
    case 326: keysym=XK_Insert; break;
    case 327: keysym=XK_Control_L; break;
    case 328: keysym=XK_Control_R; break;
    case 329: keysym=XK_Caps_Lock; break;
    }
  }
    
  keycode= XKeysymToKeycode(mavlib_dpy, keysym);
     
  XQueryKeymap(mavlib_dpy, rv);

  c= keycode/8;
  r= keycode-c*8;

  if (1&(rv[c]>>r)) 
    return 0;
  else
    return 1;
#endif
#endif
}



/* Routines specific to Voodoo */

void mav_gfx3DfxModeSet(int fullscreen)
{
#if !defined(WIN32) && !defined(macintosh)
  typedef unsigned char (*FN)(int);
  FN fn;
  
  /* Look for XMesaSetFXmode function */
  fn= (FN) dlsym(mavlib_dlh, "XMesaSetFXmode");

  if (fn)
  {
    /* Execute function with correct parameters - may change in future */
    if (fullscreen)
    {
      fn(2);
    }
    else
    {
      fn(1);
    }
  }
  else
  {
    fprintf(stderr, "Warning: cound not find XMesaSetFXmode function, ignoring\n");
  }
#endif
}

int mav_gfx3DfxBoardSet(int bd)
{
  int rv=0;
#if !defined(WIN32) && !defined(macintosh)
  typedef unsigned char (*FN)(int);
  FN fn;
  
  /* Look for fxMesaSelectCurrentBoard function */
  fn= (FN) dlsym(mavlib_dlh, "fxMesaSelectCurrentBoard");

  if (fn) 
  {
    /* Execute function with correct parameters - may change in future */
    rv= fn(bd);
  }
  else
  {
    fprintf(stderr, "Warning: cound not find fxMesaSelectCurrentBoard function, ignoring\n");
  }
#endif

  return rv;
}
