/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 * ALL RIGHTS RESERVED
 * Permission to use, copy, modify, and distribute this software for
 * any purpose and without fee is hereby granted, provided that the above
 * copyright notice appear in all copies and that both the copyright notice
 * and this permission notice appear in supporting documentation, and that
 * the name of Silicon Graphics, Inc. not be used in advertising
 * or publicity pertaining to distribution of the software without specific,
 * written prior permission.
 *
 * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
 * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
 * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
 * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
 * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
 * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
 * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
 * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
 * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
 * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 *
 * US Government Users Restricted Rights
 * Use, duplication, or disclosure by the Government is subject to
 * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
 * (c)(1)(ii) of the Rights in Technical Data and Computer Software
 * clause at DFARS 252.227-7013 and/or in similar or successor
 * clauses in the FAR or the DOD or NASA FAR Supplement.
 * Unpublished-- rights reserved under the copyright laws of the
 * United States.  Contractor/manufacturer is Silicon Graphics,
 * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
 *
 * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
 */

/*
 *
 * This file has been slightly modified from the original for use with Mesa
 *
 *     Jeroen van der Zijp
 *
 *     jvz@cyberia.cfdrc.com
 *
 */
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <GL/glx.h>
#include <GL/gl.h>
#ifdef __GLX_MOTIF
#include <Xm/PrimitiveP.h>
#include "GLwMDrawAP.h"
#else
#include "GLwDrawAP.h"
#endif
#include <assert.h>
#include <stdio.h>

#ifdef __GLX_MOTIF
#define GLwDrawingAreaWidget             GLwMDrawingAreaWidget
#define GLwDrawingAreaClassRec           GLwMDrawingAreaClassRec
#define glwDrawingAreaClassRec           glwMDrawingAreaClassRec
#define glwDrawingAreaWidgetClass        glwMDrawingAreaWidgetClass
#define GLwDrawingAreaRec                GLwMDrawingAreaRec
#endif

#define ATTRIBLIST_SIZE 32

#define offset(field) XtOffset(GLwDrawingAreaWidget,glwDrawingArea.field)

/* forward definitions */
static void createColormap(GLwDrawingAreaWidget w,int offset,XrmValue *value);
static void Initialize(GLwDrawingAreaWidget req,GLwDrawingAreaWidget neww,ArgList args,Cardinal *num_args);
static void Realize(Widget w,Mask *valueMask,XSetWindowAttributes *attributes);
static void Redraw(GLwDrawingAreaWidget w,XEvent *event,Region region);
static void Resize(GLwDrawingAreaWidget glw);
static void Destroy(GLwDrawingAreaWidget glw);
static void glwInput(GLwDrawingAreaWidget glw,XEvent *event,String *params,Cardinal *numParams);

static char defaultTranslations[] =
#ifdef __GLX_MOTIF
"<Key>osfHelp:PrimitiveHelp() \n"
#endif
"<KeyDown>:   glwInput() \n\
     <KeyUp>:     glwInput() \n\
     <BtnDown>:   glwInput() \n\
     <BtnUp>:     glwInput() \n\
     <BtnMotion>: glwInput() ";

static XtActionsRec actions[] =
{
   {                                              /* key or mouse input */
      (char *)"glwInput",(XtActionProc)glwInput
   },
};

/*
 * There is a bit of unusual handling of the resources here.
 * Because Xt insists on allocating the colormap resource when it is
 * processing the core resources (even if we redeclare the colormap
 * resource here, we need to do a little trick.  When Xt first allocates
 * the colormap, we allow it to allocate the default one, since we have
 * not yet determined the appropriate visual (which is determined from
 * resources parsed after the colormap).  We also let it allocate colors
 * in that default colormap.
 *
 * In the initialize proc we calculate the actual visual.  Then, we
 * reobtain the colormap resource using XtGetApplicationResources in
 * the initialize proc.  If requested, we also reallocate colors in
 * that colormap using the same method.
 */

static XtResource resources[] =
{
   /* The GLX attributes.  Add any new attributes here */

   {
      GLwNbufferSize, GLwCBufferSize, XtRInt, sizeof (int),
      offset(bufferSize), XtRImmediate, (XtPointer) 0
   },

   {
      GLwNlevel, GLwCLevel, XtRInt, sizeof (int),
      offset(level), XtRImmediate, (XtPointer) 0
   },

   {
      GLwNrgba, GLwCRgba, XtRBoolean, sizeof (Boolean),
      offset(rgba), XtRImmediate, (XtPointer) FALSE
   },

   {
      GLwNdoublebuffer, GLwCDoublebuffer, XtRBoolean, sizeof (Boolean),
      offset(doublebuffer), XtRImmediate, (XtPointer) FALSE
   },

   {
      GLwNstereo, GLwCStereo, XtRBoolean, sizeof (Boolean),
      offset(stereo), XtRImmediate, (XtPointer) FALSE
   },

   {
      GLwNauxBuffers, GLwCAuxBuffers, XtRInt, sizeof (int),
      offset(auxBuffers), XtRImmediate, (XtPointer) 0
   },

   {
      GLwNredSize, GLwCColorSize, XtRInt, sizeof (int),
      offset(redSize), XtRImmediate, (XtPointer) 1
   },

   {
      GLwNgreenSize, GLwCColorSize, XtRInt, sizeof (int),
      offset(greenSize), XtRImmediate, (XtPointer) 1
   },

   {
      GLwNblueSize, GLwCColorSize, XtRInt, sizeof (int),
      offset(blueSize), XtRImmediate, (XtPointer) 1
   },

   {
      GLwNalphaSize, GLwCAlphaSize, XtRInt, sizeof (int),
      offset(alphaSize), XtRImmediate, (XtPointer) 0
   },

   {
      GLwNdepthSize, GLwCDepthSize, XtRInt, sizeof (int),
      offset(depthSize), XtRImmediate, (XtPointer) 0
   },

   {
      GLwNstencilSize, GLwCStencilSize, XtRInt, sizeof (int),
      offset(stencilSize), XtRImmediate, (XtPointer) 0
   },

   {
      GLwNaccumRedSize, GLwCAccumColorSize, XtRInt, sizeof (int),
      offset(accumRedSize), XtRImmediate, (XtPointer) 0
   },

   {
      GLwNaccumGreenSize, GLwCAccumColorSize, XtRInt, sizeof (int),
      offset(accumGreenSize), XtRImmediate, (XtPointer) 0
   },

   {
      GLwNaccumBlueSize, GLwCAccumColorSize, XtRInt, sizeof (int),
      offset(accumBlueSize), XtRImmediate, (XtPointer) 0
   },

   {
      GLwNaccumAlphaSize, GLwCAccumAlphaSize, XtRInt, sizeof (int),
      offset(accumAlphaSize), XtRImmediate, (XtPointer) 0
   },

   /* the attribute list */
   {
      GLwNattribList, GLwCAttribList, XtRPointer, sizeof(int *),
      offset(attribList), XtRImmediate, (XtPointer) NULL
   },

   /* the visual info */
   {
      GLwNvisualInfo, GLwCVisualInfo, GLwRVisualInfo, sizeof (XVisualInfo *),
      offset(visualInfo), XtRImmediate, (XtPointer) NULL
   },

   /* miscellaneous resources */
   {
      GLwNinstallColormap, GLwCInstallColormap, XtRBoolean, sizeof (Boolean),
      offset(installColormap), XtRImmediate, (XtPointer) TRUE
   },

   {
      GLwNallocateBackground, GLwCAllocateColors, XtRBoolean, sizeof (Boolean),
      offset(allocateBackground), XtRImmediate, (XtPointer) FALSE
   },

   {
      GLwNallocateOtherColors, GLwCAllocateColors, XtRBoolean, sizeof (Boolean),
      offset(allocateOtherColors), XtRImmediate, (XtPointer) FALSE
   },

   {
      GLwNinstallBackground, GLwCInstallBackground, XtRBoolean, sizeof (Boolean),
      offset(installBackground), XtRImmediate, (XtPointer) TRUE
   },

   {
      GLwNginitCallback, GLwCCallback, XtRCallback, sizeof (XtCallbackList),
      offset(ginitCallback), XtRImmediate, (XtPointer) NULL
   },

   {
      GLwNinputCallback, GLwCCallback, XtRCallback, sizeof (XtCallbackList),
      offset(inputCallback), XtRImmediate, (XtPointer) NULL
   },

   {
      GLwNresizeCallback, GLwCCallback, XtRCallback, sizeof (XtCallbackList),
      offset(resizeCallback), XtRImmediate, (XtPointer) NULL
   },

   {
      GLwNexposeCallback, GLwCCallback, XtRCallback, sizeof (XtCallbackList),
      offset(exposeCallback), XtRImmediate, (XtPointer) NULL
   },

   /* Changes to Motif primitive resources */
#ifdef __GLX_MOTIF
   {
      XmNtraversalOn, XmCTraversalOn, XmRBoolean, sizeof (Boolean),
      XtOffset (GLwDrawingAreaWidget, primitive.traversal_on), XmRImmediate,
      (XtPointer)FALSE
   },

   /* highlighting is normally disabled, as when Motif tries to disable
    * highlighting, it tries to reset the color back to the parent's
    * background (usually Motif blue).  Unfortunately, that is in a
    * different colormap, and doesn't work too well.
    */
   {
      XmNhighlightOnEnter, XmCHighlightOnEnter, XmRBoolean, sizeof (Boolean),
      XtOffset (GLwDrawingAreaWidget, primitive.highlight_on_enter),
      XmRImmediate, (XtPointer) FALSE
   },

   {
      XmNhighlightThickness, XmCHighlightThickness, XmRHorizontalDimension,
      sizeof (Dimension),
      XtOffset (GLwDrawingAreaWidget, primitive.highlight_thickness),
      XmRImmediate, (XtPointer) 0
   },
#endif
};

/*
 ** The following resources are reobtained using XtGetApplicationResources
 ** in the initialize proc.
 */

/* The colormap */
static XtResource initializeResources[] =
{
   /* reobtain the colormap with the new visual */
   {
      XtNcolormap, XtCColormap, XtRColormap, sizeof(Colormap),
      XtOffset(GLwDrawingAreaWidget, core.colormap),
      XtRCallProc,(XtPointer) createColormap
   },
};

/* reallocate any colors we need in the new colormap */

/* The background is obtained only if the allocateBackground resource is TRUE*/
static XtResource backgroundResources[] =
{
#ifdef __GLX_MOTIF
   {
      XmNbackground, XmCBackground,XmRPixel,
      sizeof(Pixel),XtOffset(GLwDrawingAreaWidget,core.background_pixel),
      XmRString,(XtPointer)"lightgrey"
   },
   /*XmRCallProc,(XtPointer)_XmBackgroundColorDefault},*/

   {
      XmNbackgroundPixmap,XmCPixmap,XmRXmBackgroundPixmap,
      sizeof(Pixmap),XtOffset(GLwDrawingAreaWidget,core.background_pixmap),
      XmRImmediate,(XtPointer)XmUNSPECIFIED_PIXMAP
   },

#else
   {
      XtNbackground,XtCBackground,XtRPixel,sizeof(Pixel),
      XtOffset(GLwDrawingAreaWidget,core.background_pixel),
      XtRString,(XtPointer)"lightgrey"
   },
   /*XtRString,(XtPointer)"XtDefaultBackground"},*/

   {
      XtNbackgroundPixmap, XtCPixmap, XtRPixmap, sizeof(Pixmap),
      XtOffset(GLwDrawingAreaWidget,core.background_pixmap),
      XtRImmediate,(XtPointer)XtUnspecifiedPixmap
   },
#endif
};

/* The other colors such as the foreground are allocated only if
 * allocateOtherColors are set.  These resources only exist in Motif.
 */
#ifdef __GLX_MOTIF
static XtResource otherColorResources[] =
{
   {
      XmNforeground,XmCForeground,XmRPixel,
      sizeof(Pixel),XtOffset(GLwDrawingAreaWidget,primitive.foreground),
      XmRString,(XtPointer)"lighgrey"
   },
   /*XmRCallProc, (XtPointer) _XmForegroundColorDefault},*/

   {
      XmNhighlightColor,XmCHighlightColor,XmRPixel,sizeof(Pixel),
      XtOffset(GLwDrawingAreaWidget,primitive.highlight_color),
      XmRString,(XtPointer)"lightgrey"
   },
   /*XmRCallProc,(XtPointer)_XmHighlightColorDefault},*/

   {
      XmNhighlightPixmap,XmCHighlightPixmap,XmRPrimHighlightPixmap,
      sizeof(Pixmap),
      XtOffset(GLwDrawingAreaWidget,primitive.highlight_pixmap),
      XmRImmediate,(XtPointer)XmUNSPECIFIED_PIXMAP
   },
   /*XmRCallProc,(XtPointer)_XmPrimitiveHighlightPixmapDefault},*/
};
#endif

#undef offset

GLwDrawingAreaClassRec glwDrawingAreaClassRec =
{
   {                                              /* core fields */
#ifdef __GLX_MOTIF
      /* superclass                */        (WidgetClass) &xmPrimitiveClassRec,
      /* class_name                */        (char *)"GLwMDrawingArea",
#else                                       /* not __GLX_MOTIF */
      /* superclass                */        (WidgetClass) &widgetClassRec,
      /* class_name                */        (char *)"GLwDrawingArea",
#endif                                      /* __GLX_MOTIF */
      /* widgetSize               */        sizeof(GLwDrawingAreaRec),
      /* class_initialize          */        NULL,
      /* class_part_initialize     */        NULL,
      /* class_inited              */        FALSE,
      /* initialize                */        (XtInitProc) Initialize,
      /* initialize_hook           */        NULL,
      /* realize                   */        Realize,
      /* actions                   */        actions,
      /* num_actions               */        XtNumber(actions),
      /* resources                 */        resources,
      /* num_resources             */        XtNumber(resources),
      /* xrm_class                 */        NULLQUARK,
      /* compress_motion           */        TRUE,
      /* compress_exposure         */        TRUE,
      /* compress_enterleave       */        TRUE,
      /* visible_interest          */        TRUE,
      /* destroy                   */        (XtWidgetProc) Destroy,
      /* resize                    */        (XtWidgetProc) Resize,
      /* expose                    */        (XtExposeProc) Redraw,
      /* set_values                */        NULL,
      /* set_values_hook           */        NULL,
      /* set_values_almost         */        XtInheritSetValuesAlmost,
      /* get_values_hook           */        NULL,
      /* accept_focus              */        NULL,
      /* version                   */        XtVersion,
      /* callback_private          */        NULL,
      /* tm_table                  */        defaultTranslations,
      /* query_geometry            */        XtInheritQueryGeometry,
      /* display_accelerator       */        XtInheritDisplayAccelerator,
      /* extension                 */        NULL
   },
#ifdef __GLX_MOTIF                             /* primitive resources */
   {
      /* border_highlight          */        XmInheritBorderHighlight,
      /* border_unhighlight        */        XmInheritBorderUnhighlight,
      /* translations              */        XtInheritTranslations,
      /* arm_and_activate          */        NULL,
      /* get_resources             */        NULL,
      /* num get_resources         */        0,
      /* extension                 */        NULL,
      
   },
#endif

{NULL}
};

WidgetClass glwDrawingAreaWidgetClass=(WidgetClass)&glwDrawingAreaClassRec;

static void error(Widget w,char* string)
{
   char buf[100];
#ifdef __GLX_MOTIF
   sprintf(buf,"GLwMDrawingArea: %s\n",string);
#else
   sprintf(buf,"GLwDrawingArea: %s\n",string);
#endif
   XtAppError(XtWidgetToApplicationContext(w),buf);
}


static void warning(Widget w,char* string)
{
   char buf[100];
#ifdef __GLX_MOTIF
   sprintf (buf, "GLwMDraw: %s\n", string);
#else
   sprintf (buf, "GLwDraw: %s\n", string);
#endif
   XtAppWarning(XtWidgetToApplicationContext(w), buf);
}


/* Initialize the attribList based on the attributes */
static void createAttribList(GLwDrawingAreaWidget w)
{
   int *ptr;
   w->glwDrawingArea.attribList = (int*)XtMalloc(ATTRIBLIST_SIZE*sizeof(int));
   if(!w->glwDrawingArea.attribList)
   {
      error((Widget)w,(char *)"Unable to allocate attribute list");
   }
   ptr = w->glwDrawingArea.attribList;
   *ptr++ = GLX_BUFFER_SIZE;
   *ptr++ = w->glwDrawingArea.bufferSize;
   *ptr++ = GLX_LEVEL;
   *ptr++ = w->glwDrawingArea.level;
   if(w->glwDrawingArea.rgba) *ptr++ = GLX_RGBA;
   if(w->glwDrawingArea.doublebuffer) *ptr++ = GLX_DOUBLEBUFFER;
   if(w->glwDrawingArea.stereo) *ptr++ = GLX_STEREO;
   *ptr++ = GLX_AUX_BUFFERS;
   *ptr++ = w->glwDrawingArea.auxBuffers;
   *ptr++ = GLX_RED_SIZE;
   *ptr++ = w->glwDrawingArea.redSize;
   *ptr++ = GLX_GREEN_SIZE;
   *ptr++ = w->glwDrawingArea.greenSize;
   *ptr++ = GLX_BLUE_SIZE;
   *ptr++ = w->glwDrawingArea.blueSize;
   *ptr++ = GLX_ALPHA_SIZE;
   *ptr++ = w->glwDrawingArea.alphaSize;
   *ptr++ = GLX_DEPTH_SIZE;
   *ptr++ = w->glwDrawingArea.depthSize;
   *ptr++ = GLX_STENCIL_SIZE;
   *ptr++ = w->glwDrawingArea.stencilSize;
   *ptr++ = GLX_ACCUM_RED_SIZE;
   *ptr++ = w->glwDrawingArea.accumRedSize;
   *ptr++ = GLX_ACCUM_GREEN_SIZE;
   *ptr++ = w->glwDrawingArea.accumGreenSize;
   *ptr++ = GLX_ACCUM_BLUE_SIZE;
   *ptr++ = w->glwDrawingArea.accumBlueSize;
   *ptr++ = GLX_ACCUM_ALPHA_SIZE;
   *ptr++ = w->glwDrawingArea.accumAlphaSize;
   *ptr++ = None;
   assert((ptr-w->glwDrawingArea.attribList)<ATTRIBLIST_SIZE);
}


/* Initialize the visualInfo based on the attribute list */
static void createVisualInfo(GLwDrawingAreaWidget w)
{
   assert(w->glwDrawingArea.attribList);
   w->glwDrawingArea.visualInfo=glXChooseVisual(XtDisplay(w),XScreenNumberOfScreen(XtScreen(w)),w->glwDrawingArea.attribList);
   if(!w->glwDrawingArea.visualInfo) error((Widget)w,(char *)"requested visual not supported");
}


/* Initialize the colormap based on the visual info.
 * This routine maintains a cache of visual-infos to colormaps.  If two
 * widgets share the same visual info, they share the same colormap.
 * This function is called by the callProc of the colormap resource entry.
 */
static void createColormap(GLwDrawingAreaWidget w,int offset,XrmValue *value)
{
    
   static struct cmapCache { Visual *visual; Colormap cmap; }
   *cmapCache;
   static int cacheEntries=0;
   static int cacheMalloced=0;
   register int i;
    (void) offset;
    (void) w;
    (void) value;
   assert(w->glwDrawingArea.visualInfo);

   /* see if we can find it in the cache */
   for(i=0; i<cacheEntries; i++)
   {
      if(cmapCache[i].visual==w->glwDrawingArea.visualInfo->visual)
      {
         value->addr=(char *)(&cmapCache[i].cmap);
         return;
      }
   }

   /* not in the cache, create a new entry */
   if(cacheEntries >= cacheMalloced)
   {
      /* need to malloc a new one.  Since we are likely to have only a
       * few colormaps, we allocate one the first time, and double
       * each subsequent time.
       */
      if(cacheMalloced==0)
      {
         cacheMalloced=1;
         cmapCache=(struct cmapCache*)XtMalloc(sizeof(struct cmapCache));
      }
      else
      {
         cacheMalloced<<=1;
         cmapCache=(struct cmapCache*)XtRealloc((char*)cmapCache,sizeof(struct cmapCache)*cacheMalloced);
      }
   }

   cmapCache[cacheEntries].cmap=XCreateColormap(XtDisplay(w),
      RootWindow(XtDisplay(w),
      w->glwDrawingArea.visualInfo->screen),
      w->glwDrawingArea.visualInfo->visual,
      AllocNone);
   cmapCache[cacheEntries].visual=w->glwDrawingArea.visualInfo->visual;
   value->addr=(char *)(&cmapCache[cacheEntries++].cmap);
}


static void Initialize(GLwDrawingAreaWidget req,GLwDrawingAreaWidget neww,ArgList args,Cardinal *num_args)
{

   /* fix size */
   if(req->core.width==0) neww->core.width=100;
   if(req->core.height==0) neww->core.width=100;

   /* create the attribute list if needed */
   neww->glwDrawingArea.myList=FALSE;
   if(neww->glwDrawingArea.attribList==NULL)
   {
      neww->glwDrawingArea.myList=TRUE;
      createAttribList(neww);
   }

   /* Gotta have it */
   assert(neww->glwDrawingArea.attribList);

   /* determine the visual info if needed */
   neww->glwDrawingArea.myVisual=FALSE;
   if(neww->glwDrawingArea.visualInfo==NULL)
   {
      neww->glwDrawingArea.myVisual=TRUE;
      createVisualInfo(neww);
   }

   /* Gotta have that too */
   assert(neww->glwDrawingArea.visualInfo);

   neww->core.depth=neww->glwDrawingArea.visualInfo->depth;

   /* Reobtain the colormap and colors in it using XtGetApplicationResources*/
   XtGetApplicationResources((Widget)neww,neww,initializeResources,XtNumber(initializeResources),args,*num_args);

   /* obtain the color resources if appropriate */
   if(req->glwDrawingArea.allocateBackground)
   {
      XtGetApplicationResources((Widget)neww,neww,backgroundResources,XtNumber(backgroundResources),args,*num_args);
   }

#ifdef __GLX_MOTIF
   if(req->glwDrawingArea.allocateOtherColors)
   {
      XtGetApplicationResources((Widget)neww,neww,otherColorResources,XtNumber(otherColorResources),args,*num_args);
   }
#endif
}


static void Realize(Widget w,Mask *valueMask,XSetWindowAttributes *attributes)
{
   register GLwDrawingAreaWidget glw=(GLwDrawingAreaWidget)w;
   GLwDrawingAreaCallbackStruct cb;
   Widget parentShell;
   Status status;
   Window windows[2],*windowsReturn,*windowList;
   int countReturn,i;

   /* if we haven't requested that the background be both installed and
    * allocated, don't install it.
    */
   if(!(glw->glwDrawingArea.installBackground && glw->glwDrawingArea.allocateBackground))
   {
      *valueMask&=~CWBackPixel;
   }

   XtCreateWindow(w,(unsigned int)InputOutput,glw->glwDrawingArea.visualInfo->visual,*valueMask,attributes);

   /* if appropriate, call XSetWMColormapWindows to install the colormap */
   if(glw->glwDrawingArea.installColormap)
   {

      /* Get parent shell */
      for(parentShell=XtParent(w);
            parentShell&&!XtIsShell(parentShell);
            parentShell=XtParent(parentShell))
         ;

      if(parentShell && XtWindow(parentShell))
      {

         /* check to see if there is already a property */
         status=XGetWMColormapWindows(XtDisplay(parentShell),XtWindow(parentShell),&windowsReturn,&countReturn);

         /* if no property, just create one */
         if(!status)
         {
            windows[0]=XtWindow(w);
            windows[1]=XtWindow(parentShell);
            XSetWMColormapWindows(XtDisplay(parentShell),XtWindow(parentShell),windows,2);
         }

         /* there was a property, add myself to the beginning */
         else
         {
            windowList=(Window *)XtMalloc((sizeof(Window))*(countReturn+1));
            windowList[0]=XtWindow(w);
            for(i=0; i<countReturn; i++) windowList[i+1]=windowsReturn[i];
            XSetWMColormapWindows(XtDisplay(parentShell),XtWindow(parentShell),windowList,countReturn+1);
            XtFree((char*)windowList);
            XtFree((char*)windowsReturn);
         }
      }
      else
      {
         warning(w,(char *)"Could not set colormap property on parent shell");
      }
   }

   /* Invoke callbacks */
   cb.reason=GLwCR_GINIT;
   cb.event=NULL;
   cb.width=glw->core.width;
   cb.height=glw->core.height;
   XtCallCallbackList((Widget)glw,glw->glwDrawingArea.ginitCallback,&cb);
}


static void Redraw(GLwDrawingAreaWidget w,XEvent *event,Region region)
{
   
   GLwDrawingAreaCallbackStruct cb;
   (void) region; 
   if(!XtIsRealized((Widget)w)) return;
   cb.reason=GLwCR_EXPOSE;
   cb.event=event;
   cb.width=w->core.width;
   cb.height=w->core.height;
   XtCallCallbackList((Widget)w,w->glwDrawingArea.exposeCallback,&cb);
}


static void Resize(GLwDrawingAreaWidget glw)
{
   GLwDrawingAreaCallbackStruct cb;
   if(!XtIsRealized((Widget)glw)) return;
   cb.reason=GLwCR_RESIZE;
   cb.event=NULL;
   cb.width=glw->core.width;
   cb.height=glw->core.height;
   XtCallCallbackList((Widget)glw,glw->glwDrawingArea.resizeCallback,&cb);
}


static void Destroy(GLwDrawingAreaWidget glw)
{
   Window *windowsReturn;
   Widget parentShell;
   Status status;
   int countReturn;
   register int i;

   if(glw->glwDrawingArea.myList && glw->glwDrawingArea.attribList)
   {
      XtFree((char *)glw->glwDrawingArea.attribList);
   }

   if(glw->glwDrawingArea.myVisual && glw->glwDrawingArea.visualInfo)
   {
      XtFree((char *)glw->glwDrawingArea.visualInfo);
   }

   /* if my colormap was installed, remove it */
   if(glw->glwDrawingArea.installColormap)
   {

      /* Get parent shell */
      for(parentShell=XtParent(glw);
            parentShell&&!XtIsShell(parentShell);
            parentShell=XtParent(parentShell))
         ;

      if(parentShell && XtWindow(parentShell))
      {

         /* make sure there is a property */
         status=XGetWMColormapWindows(XtDisplay(parentShell),XtWindow(parentShell),&windowsReturn,&countReturn);

         /* if no property, just return.  If there was a property, continue */
         if(status)
         {

            /* search for a match */
            for(i=0; i<countReturn; i++)
            {
               if(windowsReturn[i]==XtWindow(glw))
               {

                  /* we found a match, now copy the rest down */
                  for(i++; i<countReturn; i++){ windowsReturn[i-1]=windowsReturn[i]; }

                  XSetWMColormapWindows(XtDisplay(parentShell),XtWindow(parentShell),windowsReturn,countReturn-1);
                  break;
               }
            }
            XtFree((char *)windowsReturn);
         }
      }
   }
}


/* Action routine for keyboard and mouse events */
static void glwInput(GLwDrawingAreaWidget glw,XEvent *event,String *params,Cardinal *numParams)
{
    
   GLwDrawingAreaCallbackStruct cb;
   (void) params;
    (void) numParams;
   cb.reason=GLwCR_INPUT;
   cb.event=event;
   cb.width=glw->core.width;
   cb.height=glw->core.height;
   XtCallCallbackList((Widget)glw,glw->glwDrawingArea.inputCallback,&cb);
}


#ifdef __GLX_MOTIF

/* Create routine */
Widget GLwCreateMDrawingArea(Widget parent, char *name,ArgList arglist,Cardinal argcount)
{
   return XtCreateWidget(name,glwMDrawingAreaWidgetClass, parent, arglist,argcount);
}
#endif

#ifndef __GLX_MOTIF

/* Make context current */
void GLwDrawingAreaMakeCurrent(Widget w,GLXContext ctx)
{
   glXMakeCurrent(XtDisplay(w),XtWindow(w),ctx);
}


/* Swap buffers convenience function */
void GLwDrawingAreaSwapBuffers(Widget w)
{
   glXSwapBuffers(XtDisplay(w),XtWindow(w));
}
#endif
