/* 21/11/00 - added left/right shift/alt/ctrl          */
/* 08/11/00 - added font sizing and multiple font support */
/* font sizing needs update to src/kernel/mav_frame.c  */
/* minimum window resize                               */
/* tidy up loose handles on exit                       */
/* 29/10/00 - added enter/leave event handling         */
/*  (so mav_win_mouse gets correctly set)              */
/* changed from 5.4 - 27/1/2000, 18/10/00, 26/10/00    */
/* changes:                                            */
/* map/unmap event handled                             */
/* minor change to WM_PAINT event handling             */
/* single buffer and accum buffer flags work           */
/* windows share contexts                              */
/* expose event handled                                */
/* (most) punctuation chars reported correctly         */
/* mouse buttons polling works                         */
/* window size adjusted for title/border               */
/* uses mouse capture to avoid missing button ups      */
/* minor changes to window creation/event handling     */
/* events now return mouse position at time of event   */
/* fullscreen mode supported                           */

/* note for fullscreen:                                        */
/*   if mav_opt_fullscreen is set then ${HOME}/.mav_fullscreen */
/*   is read in for the width, height and bitdepth of the      */
/*   display mode, or if not found, the value MAVLIB_WIDTH,    */
/*   MAVLIB_HEIGHT and MAVLIB_BITS are used. If the display    */
/*   mode cannot be changed the application is run windowed.   */
/*   I tried to implement <ctrl>-F1 switching between windowed */
/*   and fullscreen modes but this requires changing the pixel */
/*   format and SetPixelFormat really does *not* like being    */
/*   called multiple times.                                    */

/*
 GNU Maverik - a system for managing display and interaction in 
               Virtual Environment applications.
 Copyright (C) 1999-2000 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 */

#ifdef __cplusplus
extern "C" {
#endif
void mav_gfxWindowOpen(int id, int x, int y, int w, int h, char *name, char *disp, int wmp, int sb, int qb, int ms, int ab, int stenb, int desta, int *wret, int *hret);
void mav_gfxWindowClose(int id);
void mav_gfxWindowSet(int id);
void mav_gfxWindowBuffersSwap(void);
void mav_gfxWindowResGet(int *x, int *y);
int  mav_gfxWindowEventGet(int *info);
int  mav_gfxWindowEventPeek(void);
int  mav_gfxWindowPointerGet(int id, int *x, int *y, int *rx, int *ry, int *buts);
void mav_gfxWindowPointerSet(int win, int x, int y);
int  mav_gfxWindowKeyGet(int key);
int  mav_gfxWindowFontSet(char *s, int font, int *width);
void mav_gfxWindowStringDisplay(char *s, int font);
void mav_moduleNew(char *fn(void));
int  mav_gfxModuleInit(void);
char *mav_gfxModuleID(void);
void mav_gfx3DfxModeSet(int fullscreen);
int  mav_gfx3DfxBoardSet(int bd);
#ifdef __cplusplus
}
#endif
#define MAX_WINS 10 /* Make sure the same or greater than equivalent in mav_kernel.h */
#define MAX_FONTS 10 /* Same as above */
#define MAX_DPYS 8
extern int mav_opt_bindTextures;
extern int mav_opt_shareContexts;
extern int mav_opt_maxTextures;
extern int mavlib_voodoo;
extern void *mavlib_dlh;
extern char *mav_gfx_vendor;
extern char *mav_gfx_renderer;
extern char *mav_gfx_version;



/* 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


#if defined(GL_VERSION_1_1) || defined(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
typedef struct {
  char *name;
  Display *dpy;
  Window rootwin;
  int scrnum;
} MAVLIB_dpyhand;

MAVLIB_dpyhand mavlib_dpy[MAX_DPYS];
int mavlib_quadId=-1;
#endif

#ifdef WIN32
/* defines for default fullscreen mode */
#define MAVLIB_WIDTH 320
#define MAVLIB_HEIGHT 240
#define MAVLIB_BITS 16

/* font handles */
HFONT mavlib_fonts[MAX_FONTS];

/* fullscreen mode variables */
int mavlib_gfx_width= -1;
int mavlib_gfx_height= -1;
int mavlib_gfx_bits= -1;

extern int mav_opt_fullscreen;

int mavlib_gfx_fullscreen= -1;

/* mav_win_mouse HWND */
HWND mavlib_hwnd= NULL;
#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;
  PIXELFORMATDESCRIPTOR pfd;
  int width;
  int height;
  int resized;
  int exposed;
  int mapped;
  TRACKMOUSEEVENT tme;
  int enter;
  int leave;
#else
  int dpy;
  Window win;
#ifdef MAV_IRISGL
#else
  GLXContext ctx;
#endif
  int quad;
  int quad_separate;
#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
}

#ifdef WIN32
int mav_gfxStringLength (int win, char *s, int font)
{
/* returns the width of the text in the given font */
  SIZE size;

  SelectObject (mavlib_winhand[win].hdc, mavlib_fonts[font]);
  GetTextExtentPoint32 (mavlib_winhand[win].hdc, s,
		strlen (s), &size);

  return size.cx;
}
#endif

void mavlib_gfxExit(void)
{
#ifndef MAV_NONE
  int i;
#ifdef WIN32
/* delete font handles */
  for (i=0; i<MAX_FONTS; i++) {
    if (mavlib_fonts[i]) DeleteObject (mavlib_fonts[i]);
  }

   /* shut down windows nicely */
  for (i=0; i<MAX_WINS; i++) {
    if (mavlib_winhand[i].win) {
      ReleaseDC (mavlib_winhand[i].win, mavlib_winhand[i].hdc);
/* only delete gl contexts created by that window */
      if (!mav_opt_shareContexts || i==1)
	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
#if 0 /* Causing problem on NVIDIA cards */
  /* 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].dpy].dpy, mavlib_winhand[i].win);
  }
#endif


  for (i=0; i<MAX_DPYS; i++) if (mavlib_dpy[i].dpy) XSync(mavlib_dpy[i].dpy, False);
#endif
#endif
}

#ifndef MAV_NONE
#if !defined(WIN32) && !defined(macintosh)
void mavlib_XOpen(int id, char *nm)
{
  mavlib_dpy[id].dpy= XOpenDisplay(nm);

  if (!mavlib_dpy[id].dpy) {
    fprintf(stderr, "Error: cannot connect to X server %s\n", XDisplayName(nm));
    exit(1);
  }

  mavlib_dpy[id].scrnum= DefaultScreen(mavlib_dpy[id].dpy);
  mavlib_dpy[id].rootwin= RootWindow(mavlib_dpy[id].dpy, mavlib_dpy[id].scrnum);

  if (nm) {
    mavlib_dpy[id].name= (char *) malloc(sizeof(char)*(strlen(nm)+1));
    if (!mavlib_dpy[id].name) {
      fprintf(stderr, "Error: failed to malloc X server name %s\n", nm);
      exit(1);
    }
    strcpy(mavlib_dpy[id].name, nm);
  }
}

int mavlib_XLookup(char *nm)
{
  if (nm)
  {
    int i;

    /* Look for name */
    for (i=1; i<MAX_DPYS; i++) {
      if (mavlib_dpy[i].dpy && !strcmp(mavlib_dpy[i].name, nm)) return i;
    }    

    /* Not found, open it */
    for (i=1; i<MAX_DPYS; i++) {
      if (!mavlib_dpy[i].dpy) {
	mavlib_XOpen(i, nm);
	return i;	  
      }
    }

    fprintf(stderr, "Error: maximum number of displays exceeded\n");
    exit(1);

    return 0;
  }
  else
  {
    return 0;
  }
}
#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;

/* reset font handles */
  for (i=0; i<MAX_FONTS; i++) mavlib_fonts[i]= 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;
  for (i=0; i<MAX_DPYS; i++) mavlib_dpy[i].dpy= (Display *) 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)

  /* 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_OWNDC; /* don't need CS_HREDRAW | CS_VREDRAW */
		/* CS_OWNDC is necessary for some cards */
  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_XOpen(0, NULL);
#endif

#ifndef MAV_SUNOS4
  /* clean up on application exit */
  atexit(mavlib_gfxExit);
#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[0].dpy, mavlib_dpy[0].scrnum);
  *yres= DisplayHeight(mavlib_dpy[0].dpy, mavlib_dpy[0].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].dpy].dpy, mavlib_winhand[i].win);
#else
  glXMakeCurrent(mavlib_dpy[mavlib_winhand[i].dpy].dpy, mavlib_winhand[i].win, mavlib_winhand[i].ctx);


  if (mavlib_winhand[i].quad) {
    if (mavlib_winhand[i].quad==-1) 
    {
      glDrawBuffer(GL_BACK_LEFT);
      if (!mavlib_winhand[i].quad_separate) glClear(GL_DEPTH_BUFFER_BIT);
    }
    else
    {
      glDrawBuffer(GL_BACK_RIGHT);
      if (!mavlib_winhand[i].quad_separate) glClear(GL_DEPTH_BUFFER_BIT);
    }
  }
#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
  if (mavlib_winhand[mavlib_currwin].quad<=0) glXSwapBuffers(mavlib_dpy[mavlib_winhand[mavlib_currwin].dpy].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;
  int pos= 1;
  int weight= FW_NORMAL;
  BOOL italic= FALSE;
  int family= FF_SWISS;
  int height= -1;
  char typeface[100];
  int tf= 0;

/* remove previous font */
  if (mavlib_fonts[i]) DeleteObject (mavlib_fonts[i]);

/* make a vague stab at a compatible font */

/* company */
  while (s[pos] != '-') pos ++;
  pos ++;

/* typeface - you never know, it might be on the system... */
  while (s[pos] != '-') {
    typeface[tf]= s[pos];
    tf ++;
    pos ++;
  }
  typeface[tf]= (char) NULL;
  pos ++;

/* weight */
  if (s[pos]=='b') weight= FW_BOLD;
  else if (s[pos]=='m') weight= FW_MEDIUM;
  while (s[pos] != '-') pos ++;
  pos ++;

/* slant */
  if (s[pos]=='i') italic= TRUE;
  if (s[pos]=='o' && s[pos+1] != 't')
    family= FF_MODERN;
  if (s[pos]=='r' && s[pos+1]=='-')
    family= FF_ROMAN;
  while (s[pos] != '-') pos ++;
  pos ++;

/* ignored */
  while (s[pos] != '-') pos ++;
  pos ++;

/* ignored */
  while (s[pos] != '-') pos ++;
  pos ++;

/* pixel height */
  if (s[pos] != '-' && s[pos] != '*') {
    sscanf (&s[pos], "%d", &height);
  }
  while (s[pos] != '-') pos ++;
  pos ++;

/* point height - only use if no pixel height */
  if (height==-1) {
    if (s[pos] != '-' && s[pos] != '*') {
      sscanf (&s[pos], "%d", &height);
      height /= 10;
    }
  }

/* no height defined then use default */
  if (height==-1) height= 0;

/* get the font (or a near match) */
  mavlib_fonts[i]= CreateFont (height, 0, 0, 0, weight, italic, FALSE, FALSE,
	ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
	DEFAULT_PITCH|family, typeface);
 
/* make it the current font */ 
  SelectObject (mavlib_winhand[mavlib_currwin].hdc, mavlib_fonts[i]);

/* generate display lists */
  first=0;
  last=255;

  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);
/* note - we don't release the font handle because it will be needed */
/* for text width calculations */
#else
  XFontStruct *fontInfo;
  Font id;
  unsigned int first, last;
  int j;

  fontInfo = XLoadQueryFont(mavlib_dpy[0].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) {
    /*    XFreeFont(mavlib_dpy[0].dpy, fontInfo); causes problem on NVIDIA cards */
    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 */

/* flags passed to mav_gfxWindowOpen */
int mavlib_sb= 0; /* single buffer */
int mavlib_ab= 0; /* accum buffer */

HGLRC mavlib_winSetUpGL(int win_id)
{
  int pixelFormat= 0;
  HGLRC rv = 0;

  if (!mav_opt_shareContexts || win_id==1) {
/* set the pfd for this window */
    mavlib_winhand[win_id].pfd.nSize= sizeof(PIXELFORMATDESCRIPTOR);
    mavlib_winhand[win_id].pfd.nVersion= 1;
    mavlib_winhand[win_id].pfd.dwFlags= PFD_SUPPORT_OPENGL|PFD_DRAW_TO_WINDOW;

/* double/single buffer */
    if (!mavlib_sb)
      mavlib_winhand[win_id].pfd.dwFlags |= PFD_DOUBLEBUFFER;

/* rgba type */
    mavlib_winhand[win_id].pfd.iPixelType= PFD_TYPE_RGBA;

/* colour depth - may need to change to get
   acceration from graphics card */
    mavlib_winhand[win_id].pfd.cColorBits= 16;

/* alpha buffer (not supported by generic implementation) */
    mavlib_winhand[win_id].pfd.cAlphaBits= 0;

/* accum buffer */
    if (mavlib_ab)
      mavlib_winhand[win_id].pfd.cAccumBits= 16;
    else
      mavlib_winhand[win_id].pfd.cAccumBits= 0;

/* z-buffer bits - may need to change to get
   acceleration from graphics card */
    mavlib_winhand[win_id].pfd.cDepthBits= 16; 

/* no stencil buffer */
    mavlib_winhand[win_id].pfd.cStencilBits= 0;

/* aux buffers (not supported by generic implementation) */
    mavlib_winhand[win_id].pfd.cAuxBuffers= 0;

/* layer plane (ignored?) */
    mavlib_winhand[win_id].pfd.dwLayerMask= PFD_MAIN_PLANE;

  } else {
/* same pfd as mav_win_left */
    mavlib_winhand[win_id].pfd= mavlib_winhand[1].pfd;
  }

  pixelFormat= ChoosePixelFormat(mavlib_winhand[win_id].hdc, &mavlib_winhand[win_id].pfd);

  if (pixelFormat) {
    if (SetPixelFormat(mavlib_winhand[win_id].hdc, pixelFormat, &mavlib_winhand[win_id].pfd)) {
      PIXELFORMATDESCRIPTOR pfdnew;

      DescribePixelFormat (mavlib_winhand[win_id].hdc, pixelFormat,
		sizeof (PIXELFORMATDESCRIPTOR), &pfdnew);
      if (pfdnew.dwFlags & PFD_GENERIC_FORMAT) fprintf (stderr, "Generic ICD\n");
      else fprintf (stderr, "Not generic ICD\n");
      fprintf (stderr, "%d colour bits\n", pfdnew.cColorBits);
      fprintf (stderr, "%d depth bits\n", pfdnew.cDepthBits);

/* create context if necessary */
      if (!mav_opt_shareContexts || win_id==1) {
/* new context for this window */

	rv= wglCreateContext(mavlib_winhand[win_id].hdc);
      } else {
/* shared context with mav_win_left */
	rv= mavlib_winhand[1].ctx;
      }

      if (rv) {
	if (!wglMakeCurrent(mavlib_winhand[win_id].hdc, rv)) {
	  wglDeleteContext(rv);
	  rv=0;
	}
      }
    }
  }

  return rv;
}

/* function to get the mouse position associated with an event */
void mavlib_msgPointerGet (int win, int *x, int *y, int *rx, int *ry)
{
  DWORD mouse_pos;
  POINT point;

/* get the mouse position at the time of the last message */
  mouse_pos= GetMessagePos ();
  point.x= LOWORD(mouse_pos);
  point.y= HIWORD(mouse_pos);

  *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;
}


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 */
int mavlib_win32MouseCaught= 0; /* count of capture requests */
/* button press windows */
HWND mavlib_win32MouseWin[4]= {NULL, NULL, NULL, NULL};
int mavlib_win32MouseEventsPending= 0; /* for flushing button up events */

/* This callback executed by DispatchMessage in mav_gfxWindowEventGet */

LONG WINAPI mavlib_winEventHandler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam) 
{
  LONG rv= 1;
  int v1=-1, v2=-1;
  LPMINMAXINFO mmi;
  char ch;

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

  switch (umsg) {
  case WM_GETMINMAXINFO:
/* this message is sent when the window is being resized */
    mmi= (LPMINMAXINFO) lparam;
/* make the (client) min track height 1 */
    mmi->ptMinTrackSize.y ++;
    return 0;
  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_win32Create);

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

      mavlib_winhand[mavlib_win32Create].tme.cbSize= sizeof (TRACKMOUSEEVENT);
      mavlib_winhand[mavlib_win32Create].tme.dwFlags= TME_LEAVE;
      mavlib_winhand[mavlib_win32Create].tme.hwndTrack= hwnd;
    }
    else
    {
      fprintf(stderr, "Error: unexpected create message\n");
      exit(1);
    }
    break;

  case WM_DESTROY:
/* restore display mode on exit */
    if (mavlib_gfx_fullscreen) {
      mavlib_gfx_fullscreen= 0;
      ChangeDisplaySettings (NULL, 0);
    }
    break;

  case WM_CLOSE: /* Pressed on close icon */
    if (mavlib_gfx_fullscreen) {
      mavlib_gfx_fullscreen= 0;
      ChangeDisplaySettings (NULL, 0);
    }
    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 at time of message */
    mavlib_msgPointerGet(mavlib_win32EventInfo[0], &mavlib_win32EventInfo[1], &mavlib_win32EventInfo[2], &mavlib_win32EventInfo[3], &mavlib_win32EventInfo[4]);
 

    /* 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:
	ch= lparam >> 16;
	if (ch==MapVirtualKey (VK_SHIFT, 0))
	  mavlib_win32EventInfo[6]= 318; /* left shift */
	else
	  mavlib_win32EventInfo[6]= 319; /* right shift */
	break;
    case VK_MENU:
	if (lparam & (1<<24))
	  mavlib_win32EventInfo[6]= 321; /* right alt */
	else
	  mavlib_win32EventInfo[6]= 320; /* left alt */
	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:
	if (lparam & (1<<24)) {
	  mavlib_win32EventInfo[6]= 328; /* right ctrl */
	} else {
/* a left control is sent before some right alt events - check next */
/* message to see if we should ignore this one */
	  MSG key_msg;

	  if (PeekMessage (&key_msg, hwnd, WM_KEYFIRST, WM_KEYLAST,
			PM_NOREMOVE)) {
	    if ((key_msg.lParam & (1<<24)) && key_msg.wParam==VK_MENU) {
/* remove from event queue if it's a right alt event */
	      PeekMessage (&key_msg, hwnd, WM_KEYFIRST, WM_KEYLAST,
			PM_REMOVE);
	      mavlib_win32EventInfo[6]= 321; /* right alt */
	    } else {
	      mavlib_win32EventInfo[6]= 327; /* left ctrl */
	    }
	  } else {
	    mavlib_win32EventInfo[6]= 327; /* left ctrl */
	  }
	}
	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;

    /* check for shift key and change punctuation characters */
/* £ and ¬ work inside Maverik (when displaying text), but will */
/* probably give different characters when outputting to a file, */
/* or to the terminal */
    if (mavlib_win32EventInfo[7]) {
      switch (mavlib_win32EventInfo[6]) {
	case '`': mavlib_win32EventInfo[6]= '¬'; break;
        case '1': mavlib_win32EventInfo[6]= '!'; break;
        case '2': mavlib_win32EventInfo[6]= '\"'; break;
        case '3': mavlib_win32EventInfo[6]= '£'; break;
        case '4': mavlib_win32EventInfo[6]= '$'; break;
        case '5': mavlib_win32EventInfo[6]= '%'; break;
        case '6': mavlib_win32EventInfo[6]= '^'; break;
        case '7': mavlib_win32EventInfo[6]= '&'; break;
        case '8': mavlib_win32EventInfo[6]= '*'; break;
        case '9': mavlib_win32EventInfo[6]= '('; break;
        case '0': mavlib_win32EventInfo[6]= ')'; break;
        case '-': mavlib_win32EventInfo[6]= '_'; break;
        case '=': mavlib_win32EventInfo[6]= '+'; break;
        case '\\': mavlib_win32EventInfo[6]= '|'; break;
        case '[': mavlib_win32EventInfo[6]= '{'; break;
        case ']': mavlib_win32EventInfo[6]= '}'; break;
        case ';': mavlib_win32EventInfo[6]= ':'; break;
        case '\'': mavlib_win32EventInfo[6]= '@'; break;
        case '#': mavlib_win32EventInfo[6]= '~'; break;
        case ',': mavlib_win32EventInfo[6]= '<'; break;
        case '.': mavlib_win32EventInfo[6]= '>'; break;
        case '/': mavlib_win32EventInfo[6]= '?'; break;
	default: /* do nothing */;
      }
    }

    /* 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;

/* catch the mouse to trap button up events */
    if (v2==0) { /* button pressed */
/* catch the mouse */
      if (!mavlib_win32MouseCaught) SetCapture (hwnd); 
      mavlib_win32MouseWin[v1]= hwnd; /* store the window for this event */
      mavlib_win32MouseCaught ++; /* keep count of number of captures */
    } else {
/* release the mouse */
      mavlib_win32MouseCaught --;
      mavlib_win32MouseWin[v1]= NULL;
      if (!mavlib_win32MouseCaught) {
        ReleaseCapture ();
      }
    }

    /* 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 */
    mavlib_msgPointerGet(mavlib_win32EventInfo[0], &mavlib_win32EventInfo[1], &mavlib_win32EventInfo[2], &mavlib_win32EventInfo[3], &mavlib_win32EventInfo[4]);


    /* 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_MOUSEMOVE:
    if (hwnd != mavlib_hwnd) {
      v1= mavlib_winlookup (hwnd);
      mavlib_winhand[v1].enter= 1;
      mavlib_hwnd= hwnd;
    }
/* TrackMouseEvent anyway to catch crossing mess ups */
    TrackMouseEvent (&mavlib_winhand[v1].tme);
    break;
  case WM_MOUSELEAVE:
    mavlib_winhand[mavlib_winlookup(hwnd)].leave= 1;
/* reset mavlib_hwnd unless already changed */
/* (enter events of the next window may be processed first) */
    if (mavlib_hwnd==hwnd) mavlib_hwnd= NULL;
    break;
  case WM_SIZE:  /* Resize event - store in winhand for now */
    v1= mavlib_winlookup(hwnd);
    if (wparam==SIZE_MINIMIZED) {
      mavlib_winhand[v1].mapped= 2; /* unmap (+1) */
    } else {
      mavlib_winhand[v1].width= LOWORD(lparam);
      mavlib_winhand[v1].height= HIWORD(lparam);
      mavlib_winhand[v1].resized= 1;
    }
    break;
  case WM_QUERYOPEN: /* sent before opening an iconic window */
    v1= mavlib_winlookup(hwnd);
    mavlib_winhand[v1].mapped= 1; /* map (+1) */
    break;
  case WM_PAINT: /* expose event */
/* WM not happy unless you validate the update region */
/* NULL validates the whole window */
    ValidateRect (hwnd, NULL);
    v1= mavlib_winlookup(hwnd);
/* store for checking in mav_gfxWindowEventGet */
    mavlib_winhand[v1].exposed= 1;
    break;
  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, char *disp, int wmplacement, int sb, int qb, int ms, int ab, int stenb, int desta, int *wret, int *hret)
{
#ifdef MAV_NONE
  *wret= width;
  *hret= height;
#else
#ifdef WIN32
  RECT wr;

  if (mav_opt_fullscreen==1)
    mavlib_gfx_fullscreen= 1;
  else
    mavlib_gfx_fullscreen= 0;

  if (qb) {
    fprintf(stderr, "Quad buffer visuals not supported on this platform\n");
    exit(1);
  }

  if (ms) {
    fprintf(stderr, "Multisampled visuals not supported on this platform\n");
    exit(1);
  }

/* stencil buffers are supported - add later */
  if (stenb) {
    fprintf(stderr, "Stencil buffer visuals not supported on this platform\n");
    exit(1);
  }

  if (desta) {
    fprintf(stderr, "Destination alpha buffer visuals not supported on this platform\n");
    exit(1);
  }

  if (mavlib_gfx_fullscreen) {
/* change display mode */
    DEVMODE dmSS;
    FILE *fp;
    char fname[1000];

/* get mode parameters */
    if (mavlib_gfx_width==-1||mavlib_gfx_height==-1||
		mavlib_gfx_bits==-1) {
/* try from file first */
      sprintf (fname, "%s/.mav_fullscreen", getenv("HOME"));
      fp= fopen (fname,"r");
      if (fp) {
	fscanf (fp, "%d %d %d", &mavlib_gfx_width, &mavlib_gfx_height,
		&mavlib_gfx_bits);
        fclose (fp);
      }
    }

    if (mavlib_gfx_width==-1||mavlib_gfx_height==-1||
		mavlib_gfx_bits==-1) {
/* usr defaults */
      mavlib_gfx_width= MAVLIB_WIDTH;
      mavlib_gfx_height= MAVLIB_HEIGHT;
      mavlib_gfx_bits= MAVLIB_BITS;
    }

    memset (&dmSS,0,sizeof(DEVMODE));
    dmSS.dmSize= sizeof(DEVMODE);
    dmSS.dmPelsWidth= mavlib_gfx_width;
    dmSS.dmPelsHeight= mavlib_gfx_height;
    dmSS.dmBitsPerPel= mavlib_gfx_bits;
    dmSS.dmFields= DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

    if (ChangeDisplaySettings (&dmSS, CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) {
      fprintf (stderr, "Couldn't change to fullscreen\n");
      mavlib_gfx_fullscreen= 0;
    } else {
      x= 0;
      y= 0;
      width= mavlib_gfx_width;
      height= mavlib_gfx_height;
    }
  }

/* assume we'll get the correct window size */
/* probably ought to check it (after the initial resize event) */
  *wret= width;
  *hret= height;

/* get window size with borders so we get a client area of the desired size */
  if (!mavlib_gfx_fullscreen) {
    wr.left= x;
    wr.right= width+x;
    wr.top= y;
    wr.bottom= height+y;

    if (AdjustWindowRect (&wr, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW, FALSE)) {
      x= wr.left;
      y= wr.top;
      width= wr.right-x;
      height= wr.bottom-y;
    }
  }

/* set values for WM_CREATE event */
  mavlib_win32Create=id;
  mavlib_sb= sb;
  mavlib_ab= ab;

  if (mavlib_gfx_fullscreen) {
    mavlib_winhand[id].win= CreateWindowEx(WS_EX_TOPMOST, "Maverik", nm,
		 WS_POPUP,
                 0,0, width, height,
                 NULL, NULL, mavlib_dpy, NULL);
  } else {
    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;

/* set event values */
  mavlib_winhand[id].width=-1;
  mavlib_winhand[id].height=-1;
  mavlib_winhand[id].resized=0;
  mavlib_winhand[id].exposed= 0;
  mavlib_winhand[id].mapped= 0;
  mavlib_winhand[id].enter= 0;
  mavlib_winhand[id].leave= 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);

/* at this point a resize event will have occurred but (hopefully) */
/* to the size that was originally chosen */


#elif defined(macintosh)
  AGLDrawable win;
  AGLPixelFormat fmt;
  AGLContext ctx;
  Rect rect;
  Str255 title;
  GLint attrib[20];
  int i=0;

  if (qb) {
    fprintf(stderr, "Quad buffer visuals not supported on this platform\n");
    exit(1);
  }

  if (ms) {
    fprintf(stderr, "Multisampled visuals not supported on this platform\n");
    exit(1);
  }

  if (stenb) {
    fprintf(stderr, "Stencil buffer visuals not supported on this platform\n");
    exit(1);
  }

  if (desta) {
    fprintf(stderr, "Destination alpha buffer visuals not supported on this platform\n");
    exit(1);
  }

  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++;
#ifndef MAV_MACNOACC
  attrib[i] = AGL_ALL_RENDERERS; i++;
  attrib[i] = AGL_ACCELERATED; i++;
#endif  
  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 the requested 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;

  fprintf(stderr, "\n*** IrisGL is no longer actively supported\n");
  fprintf(stderr, "*** Graphics functionality may differ from the OpenGL version\n\n");

  mavlib_winhand[id].dpy= mavlib_XLookup(disp);

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

  if ((retconfig = GLXgetconfig(mavlib_dpy[mavlib_winhand[id].dpy].dpy, mavlib_dpy[mavlib_winhand[id].dpy].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[mavlib_winhand[id].dpy].dpy);
        visinfo = XGetVisualInfo(mavlib_dpy[mavlib_winhand[id].dpy].dpy, VisualScreenMask | VisualIDMask, &template, &nret);
      }
    }
  }

#else

  int attrib[50];
  int ac=7;

  if (qb) {
    fprintf(stderr, "Quad buffer visuals not supported on this platform\n");
    exit(1);
  }

  mavlib_winhand[id].dpy= mavlib_XLookup(disp);

  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;

  if (desta) {
    attrib[ac]= GLX_ALPHA_SIZE; ac++;
    attrib[ac]= 1; ac++;
  }

  attrib[ac]= GLX_DEPTH_SIZE; ac++;
  attrib[ac]= 1; ac++;
  
  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++;
    if (desta) {
      attrib[ac]= GLX_ACCUM_ALPHA_SIZE; ac++;
      attrib[ac]= 1; ac++;
    }
  }

  if (stenb) {
    attrib[ac]= GLX_STENCIL_SIZE; ac++;
    attrib[ac]= 1; ac++;
  }

#ifdef GL_SGIS_multisample
  if (ms) {
    attrib[ac]= GLX_SAMPLES_SGIS; ac++;
    attrib[ac]= 4; ac++;
  }
#endif

  if (qb) 
  {
    if (qb==3) /* Make sure this is equal to MAV_STEREO_QUAD_BUFFERS_SEPARATE_Z defined in mav_windows.h */
    {
      mavlib_winhand[id].quad_separate= 1;
    }
    else
    {
      mavlib_winhand[id].quad_separate= 0;
    }

    if (mavlib_quadId==-1)
    {
      attrib[ac]= GLX_STEREO; ac++;
      mavlib_quadId= id;
      mavlib_winhand[id].quad= -1;
    }
    else
    {
      mavlib_winhand[id].win= mavlib_winhand[mavlib_quadId].win;
      mavlib_winhand[id].ctx= mavlib_winhand[mavlib_quadId].ctx;
      mavlib_winhand[id].quad= mavlib_quadId;

      mavlib_quadId= -1;

      *wret= width;
      *hret= height;

      mav_gfxWindowSet(id);

      return;
    }
  }
  else
  {
    mavlib_winhand[id].quad= 0;
  }


  attrib[ac]= None;

  visinfo= glXChooseVisual(mavlib_dpy[mavlib_winhand[id].dpy].dpy, mavlib_dpy[mavlib_winhand[id].dpy].scrnum, attrib);
  if (!visinfo) {
    fprintf(stderr, "Error: couldn't get an RGB");
    if (desta) fprintf(stderr, "A");
    if (!sb) fprintf(stderr, ", double-buffered");
    if (ms) fprintf(stderr, ", multi-sampled");
    if (ab) fprintf(stderr, ", acculmation-buffered");
    if (stenb) fprintf(stderr, ", stencil-buffered");
    if (qb) fprintf(stderr, ", quad-buffered");
    fprintf (stderr, " visual\n");
    exit(1);
  }

#endif

  cmap=XCreateColormap(mavlib_dpy[mavlib_winhand[id].dpy].dpy, mavlib_dpy[mavlib_winhand[id].dpy].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_winhand[id].dpy].dpy, mavlib_dpy[mavlib_winhand[id].dpy].scrnum);
  attr.background_pixel=BlackPixel(mavlib_dpy[mavlib_winhand[id].dpy].dpy, mavlib_dpy[mavlib_winhand[id].dpy].scrnum);
  attr_flags = CWColormap | CWEventMask | CWBorderPixel | CWBackPixel;

   /* Create the window */
  mavlib_winhand[id].win = XCreateWindow(mavlib_dpy[mavlib_winhand[id].dpy].dpy, mavlib_dpy[mavlib_winhand[id].dpy].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].dpy].dpy, mavlib_winhand[id].win, &tp, &tp, 0, 0, 0, 0, &ch);
  XFree(tp.value);

  /* Reposition window to requested position (window manager may not comply) */
  if (!wmplacement) {
    sh.flags = USPosition | USSize;
    XSetWMProperties(mavlib_dpy[mavlib_winhand[id].dpy].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].dpy].dpy, mavlib_winhand[id].win);

  do {
    XNextEvent(mavlib_dpy[mavlib_winhand[id].dpy].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].dpy].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[mavlib_winhand[id].dpy].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[mavlib_winhand[id].dpy].dpy, visinfo, NULL, True);
  }
  else
  {
    mavlib_winhand[id].ctx= glXCreateContext(mavlib_dpy[mavlib_winhand[id].dpy].dpy, visinfo, mavlib_winhand[1].ctx, True);
  }

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

  XFree(visinfo);
#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);
  }
#else
  /* Get graphics vendor info */
  if (!mav_gfx_vendor) mav_gfx_vendor= (char *) glGetString(GL_VENDOR);
  if (!mav_gfx_renderer) mav_gfx_renderer= (char *) glGetString(GL_RENDERER);
  if (!mav_gfx_version) mav_gfx_version= (char *) glGetString(GL_VERSION);  
#endif

  if (id==1 && mav_opt_bindTextures) {
#ifdef MAV_SUNOS4
    fprintf(stderr, "Warning: bind texture extension not available on SunOS4, ignoring.\n");
#else
#if defined(GL_VERSION_1_1) || defined(GL_EXT_texture_object)
    mavlib_bindTextureIndex= (GLuint *) malloc(mav_opt_maxTextures*3*sizeof(GLuint));
    if (!mavlib_bindTextureIndex) fprintf(stderr, "Warning: bind texture malloc failed, ignoring.\n");
#ifdef GL_VERSION_1_1
    glGenTextures(mav_opt_maxTextures*3, mavlib_bindTextureIndex);
#else
    glGenTexturesEXT(mav_opt_maxTextures*3, mavlib_bindTextureIndex);
#endif
#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)
/* don't delete a shared context */
  if (!mav_opt_shareContexts || id==1)
    wglDeleteContext(mavlib_winhand[id].ctx);
  DeleteDC (mavlib_winhand[id].hdc);
  DestroyWindow(mavlib_winhand[id].win);
  mavlib_winhand[id].win= (HWND) NULL;

#else
  XDestroyWindow(mavlib_dpy[mavlib_winhand[id].dpy].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;
  int winid=0;

#ifndef MAV_NONE
#if defined(macintosh)
  EventRecord event;
  if (EventAvail (everyEvent, &event)) {
    winid= mavlib_winlookup(FrontWindow ());
    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[0].dpy, QueuedAfterReading)) {

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

    XPeekEvent(mavlib_dpy[0].dpy, &event);

    /* get the id of the window in which the event occurred */
    winid= mavlib_winlookup(event.xany.window);

    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 + (winid<<8));
}


#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 (GetOSEvent(everyEvent, &event)) {
    /* 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 + (info[0]<<8)) ;*/
		switch (onwhat) { /* test for window handling */
		    case inSysWindow:
			   SystemClick(&event, win);/* pass clicks to Desk Accessories */
			   return (rv + (info[0]<<8));
		    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 + (info[0]<<8));
		    }
		    case inContent:
		       if (info[0] != mavlib_winlookup (win)) {
		          SelectWindow (win);
		          return (rv + (info[0]<<8));
		       }
 	           break;
		    case inDrag:
		       if (info[0] != mavlib_winlookup (win)) {
		          SelectWindow (win);
		          return (rv + (info[0]<<8));
		       }
		       if (info[0]>0) DragWindow (win, event.where, &(*GetGrayRgn())->rgnBBox); return (rv + (info[0]<<8));
		       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 + (info[0]<<8));
		} /* 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 mapping, resize, expose, enter or leave events */
  for (i=0; i<MAX_WINS; i++) {
    if (mavlib_winhand[i].win && mavlib_winhand[i].mapped) {
      info[0]= i;
      info[1]= mavlib_winhand[i].mapped - 1;
      mavlib_winhand[i].mapped= 0;
      return (4 + (info[0]<<8)); /* map/unmap event */
    }
    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 + (info[0]<<8)); /* Indicates a resize event */
    }
    if (mavlib_winhand[i].win && mavlib_winhand[i].exposed) {
      info[0]= i;
      mavlib_winhand[i].exposed= 0;
      return (6 + (info[0]<<8)); /* Indicates an expose event */
    }
    if (mavlib_winhand[i].win && mavlib_winhand[i].enter) {
      info[0]= i;
      mavlib_winhand[i].enter= 0;
      info[1]= 0;
      return (5 + (info[0]<<8)); /* Indicates an enter event */
    }
    if (mavlib_winhand[i].win && mavlib_winhand[i].leave) {
      info[0]= i;
      mavlib_winhand[i].leave= 0;
      info[1]= 1;
      return (5 + (info[0]<<8)); /* Indicates a leave event */
    }
  }

/* check for released mouse capture */
/* this section isn't really necessary unless there are other processes */
/* running which capture the mouse (or you press the windows key) */
  if (mavlib_win32MouseEventsPending || mavlib_win32MouseCaught) {
    if (!GetCapture ()) {
/* mouse no longer caught - simulate button up event for all pressed buttons */
      int i;
      int not_got_one= 1;

      mavlib_win32MouseCaught= 0;

      for (i=1; not_got_one && i<4; i++) {
	if (mavlib_win32MouseWin[i]) {
	  not_got_one= 0;
	  info[0]= mavlib_winlookup (mavlib_win32MouseWin[i]);
	  mav_gfxWindowPointerGet (info[0], &info[1], &info[2], &info[3],
			&info[4], NULL);
	  info[5]= 1; /* released */
	  info[6]= i; /* button */
/* get modifier status */
	  if (GetKeyState (VK_SHIFT)<0)
	    info[7]= 1;
	  else
	    info[7]= 0;

	  if (GetKeyState (VK_CONTROL)<0)
	    info[8]= 1;
	  else
	    info[8]= 0;

	  if (GetKeyState (VK_MENU)<0)
	    info[9]= 1;
	  else
	    info[9]= 0;

	  info[10]= -999;
/* reset mouse win */
	  mavlib_win32MouseWin[i]= NULL;
	}
      }

      if (not_got_one) mavlib_win32MouseEventsPending= 0;
      else {
	mavlib_win32MouseEventsPending= 1;
	return (2 + (info[0]<<8)); /* button event */
      }
    }
  }
/* end of mouse-capture-maybe-not-necessary section */


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

    /* Deal with event - this calls the mavlib_winEventHandler callback fn */
/* no point in calling TranslateMessage as Maverik interprets virtual keys */
/* and it just sends an extra (ignored) message to the queue */
    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 */
/* this is now handled properly in mavlib_winEventHandler */

      /* 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[0].dpy, QueuedAfterReading)) {

/* Get next event - N.B. this is a blocking call */
      
    XNextEvent(mavlib_dpy[0].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 KeyRelease:
        /* Filter out key repeats */
        if(XPending(mavlib_dpy[0].dpy)) {
          XEvent nextevent;

          XPeekEvent(mavlib_dpy[0].dpy, &nextevent);
          if(nextevent.type == KeyPress &&
             nextevent.xkey.time == event.xkey.time &&
             nextevent.xkey.state == event.xkey.state &&
             nextevent.xkey.keycode == event.xkey.keycode) {
            /* Ignore KeyPress/KeyRelease pair */
            XNextEvent(mavlib_dpy[0].dpy, &nextevent);
            break;
          }
        }
	/* Fall through */

      case KeyPress:
	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[0].dpy); 
	info[1]=0;
	break;

      case LeaveNotify:
	rv=5;
	/* turn on keyboard auto repeat when leaving a Maverik window */
	XAutoRepeatOn(mavlib_dpy[0].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 + (info[0]<<8));
}



/* 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;

/* get mouse button status */
    if (buts) {
      if (GetKeyState (VK_LBUTTON)<0) buts[0]= 0;
      else buts[0]= 1;
      if (GetKeyState (VK_MBUTTON)<0) buts[1]= 0;
      else buts[1]= 1;
      if (GetKeyState (VK_RBUTTON)<0) buts[2]= 0;
      else buts[2]= 1;
     }
  }
  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].dpy].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[mavlib_winhand[win].dpy].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[0].dpy, keysym);
     
  XQueryKeymap(mavlib_dpy[0].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;
}

