/* ** License Applicability. Except to the extent portions of this file are ** made subject to an alternative license as permitted in the SGI Free ** Software License B, Version 1.1 (the "License"), the contents of this ** file are subject only to the provisions of the License. You may not use ** this file except in compliance with the License. You may obtain a copy ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: ** ** http://oss.sgi.com/projects/FreeB ** ** Note that, as provided in the License, the Software is distributed on an ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. ** ** Original Code. The Original Code is: OpenGL Sample Implementation, ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. ** Copyright in any portions created by third parties is as indicated ** elsewhere herein. All Rights Reserved. ** ** Additional Notice Provisions: The application programming interfaces ** established by SGI in conjunction with the Original Code are The ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X ** Window System(R) (Version 1.3), released October 19, 1998. This software ** was created using the OpenGL(R) version 1.2.1 Sample Implementation ** published by SGI, but has not been independently verified as being ** compliant with the OpenGL(R) version 1.2.1 Specification. ** */ /* $XFree86$ */ #include #include #include #ifdef __GLX_MOTIF #include "GLwMDrawAP.h" #else /* not __GLX_MOTIF */ #include "GLwDrawAP.h" #include #include #endif /* __GLX_MOTIF */ #include #ifdef __GLX_MOTIF /* The MOTIF version differs only in the inclusion of the primitive * widget class and in a vew variable and type name differences. * Rather than put ifdefs all over the place, we just use a few defines * to make it use motif types and names */ #define GLwDrawingAreaWidget GLwMDrawingAreaWidget #define GLwDrawingAreaClassRec GLwMDrawingAreaClassRec #define glwDrawingAreaClassRec glwMDrawingAreaClassRec #define glwDrawingAreaWidgetClass glwMDrawingAreaWidgetClass #define GLwDrawingAreaRec GLwMDrawingAreaRec #endif /* __GLX_MOTIF */ /* forward definitions */ /* resource default procs */ static void createColormap(GLwDrawingAreaWidget w, int offset, XrmValue *value); /* widget methods */ static void Initialize(GLwDrawingAreaWidget req, GLwDrawingAreaWidget new, 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); #define offset(field) XtOffset(GLwDrawingAreaWidget, glwDrawingArea.field) static char defaultTranslations[] = #ifdef __GLX_MOTIF "osfHelp:PrimitiveHelp() \n" #endif ": glwInput() \n\ : glwInput() \n\ : glwInput() \n\ : glwInput() \n\ : glwInput() "; static void glwInput(GLwDrawingAreaWidget glw, XEvent *event, String *, Cardinal *); static XtActionsRec actions[] = { { "glwInput", (XtActionProc) glwInput }, /* key or mouse input */ }; /* * 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}, #ifdef __GLX_MOTIF /* Changes to Motif primitive resources */ {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 /* __GLX_MOTIF */ }; /* 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), XmRCallProc, (XtPointer) _XmBackgroundColorDefault }, { XmNbackgroundPixmap, XmCPixmap, XmRXmBackgroundPixmap, sizeof (Pixmap), XtOffset(GLwDrawingAreaWidget, core.background_pixmap), XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP }, #else /* ! __GLX_MOTIF */ {XtNbackground, XtCBackground, XtRPixel,sizeof(Pixel), XtOffset(GLwDrawingAreaWidget,core.background_pixel), XtRString, (XtPointer)"XtDefaultBackground"}, {XtNbackgroundPixmap, XtCPixmap, XtRPixmap, sizeof(Pixmap), XtOffset(GLwDrawingAreaWidget,core.background_pixmap), XtRImmediate, (XtPointer)XtUnspecifiedPixmap}, #endif /* __GLX_MOTIF */ }; /* 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), XmRCallProc, (XtPointer) _XmForegroundColorDefault }, { XmNhighlightColor, XmCHighlightColor, XmRPixel, sizeof (Pixel), XtOffset(GLwDrawingAreaWidget, primitive.highlight_color), XmRCallProc, (XtPointer) _XmHighlightColorDefault }, { XmNhighlightPixmap, XmCHighlightPixmap, XmRPrimHighlightPixmap, sizeof (Pixmap), XtOffset(GLwDrawingAreaWidget, primitive.highlight_pixmap), XmRCallProc, (XtPointer) _XmPrimitiveHighlightPixmapDefault }, }; #endif /* __GLX_MOTIF */ struct attribInfo { int offset; int attribute; }; static struct attribInfo intAttribs[] = { { offset(bufferSize), GLX_BUFFER_SIZE }, { offset(level), GLX_LEVEL }, { offset(auxBuffers), GLX_AUX_BUFFERS }, { offset(redSize), GLX_RED_SIZE }, { offset(greenSize), GLX_GREEN_SIZE }, { offset(blueSize), GLX_BLUE_SIZE }, { offset(alphaSize), GLX_ALPHA_SIZE }, { offset(depthSize), GLX_DEPTH_SIZE }, { offset(stencilSize), GLX_STENCIL_SIZE }, { offset(accumRedSize), GLX_ACCUM_RED_SIZE }, { offset(accumGreenSize), GLX_ACCUM_GREEN_SIZE }, { offset(accumBlueSize), GLX_ACCUM_BLUE_SIZE }, { offset(accumAlphaSize), GLX_ACCUM_ALPHA_SIZE }, { 0, None }, }; static struct attribInfo booleanAttribs[] = { { offset(rgba), GLX_RGBA }, { offset(doublebuffer), GLX_DOUBLEBUFFER }, { offset(stereo), GLX_STEREO }, { 0, None }, }; #undef offset GLwDrawingAreaClassRec glwDrawingAreaClassRec = { { /* core fields */ #ifdef __GLX_MOTIF /* superclass */ (WidgetClass) &xmPrimitiveClassRec, /* class_name */ "GLwMDrawingArea", #else /* not __GLX_MOTIF */ /* superclass */ (WidgetClass) &widgetClassRec, /* class_name */ "GLwDrawingArea", #endif /* __GLX_MOTIF */ /* widget_size */ 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 /* __GLX_MOTIF */ }; 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); } /* resource initialization methods */ /* Initialize the attribList based on the attributes */ static void createAttribList(GLwDrawingAreaWidget w) { int listLength; register struct attribInfo *ap; int *ip; /* first find out how long a list we need */ listLength=1; /* include the terminating NULL */ for (ap = booleanAttribs; ap->attribute; ap++) { if (*(Boolean *)(((char *)w)+ap->offset)) listLength++; /* one word for a boolean */ } for (ap = intAttribs; ap->attribute; ap++) { if (*(int *)(((char *)w)+ap->offset)) listLength+=2; /* one word for an int */ } w->glwDrawingArea.attribList = (int *)XtMalloc(listLength*sizeof(int)); ip = w->glwDrawingArea.attribList; for (ap = booleanAttribs; ap->attribute; ap++) { if (*(Boolean *)(((char *)w)+ap->offset)) *ip++ = ap->attribute; } for (ap = intAttribs; ap->attribute; ap++) { if (*(int *)(((char *)w)+ap->offset)) { *ip++ = ap->attribute; *ip++ = *(int *)(((char *)w)+ap->offset); } } *ip = None; } /* 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,"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; int screen; } *cmapCache; static int cacheEntries=0; static int cacheMalloced=0; register int i; assert(w->glwDrawingArea.visualInfo); /* see if we can find it in the cache */ for (i=0; iglwDrawingArea.visualInfo->visual && cmapCache[i].screen == w->glwDrawingArea.visualInfo->screen) { value->addr = (XtPointer) (&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; cmapCache[cacheEntries].screen = w->glwDrawingArea.visualInfo->screen; value->addr = (XtPointer) (&cmapCache[cacheEntries++].cmap); } static void Initialize (GLwDrawingAreaWidget req, GLwDrawingAreaWidget new, ArgList args, Cardinal *num_args) { if (req->core.width == 0) new->core.width = 100; if (req->core.height == 0) new->core.width = 100; /* create the attribute list if needed */ if (new->glwDrawingArea.attribList == NULL) { new->glwDrawingArea.myList = TRUE; createAttribList(new); } else new->glwDrawingArea.myList = FALSE; /* determine the visual info if needed */ if (new->glwDrawingArea.visualInfo == NULL) { new->glwDrawingArea.myVisual = TRUE; createVisualInfo(new); } else new->glwDrawingArea.myVisual = FALSE; new->core.depth = new->glwDrawingArea.visualInfo->depth; /* Reobtain the colormap and colors in it using XtGetApplicationResources*/ XtGetApplicationResources((Widget) new, new, initializeResources, XtNumber(initializeResources), args, *num_args); /* obtain the color resources if appropriate */ if (req->glwDrawingArea.allocateBackground) XtGetApplicationResources((Widget) new, new, backgroundResources, XtNumber(backgroundResources), args, *num_args); #ifdef __GLX_MOTIF if (req->glwDrawingArea.allocateOtherColors) XtGetApplicationResources((Widget) new, new, otherColorResources, XtNumber(otherColorResources), args, *num_args); #endif /* __GLX_MOTIF */ } static void Realize(Widget w, Mask *valueMask, XSetWindowAttributes *attributes) { register GLwDrawingAreaWidget glw = (GLwDrawingAreaWidget)w; GLwDrawingAreaCallbackStruct cb; /* 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) { Widget parentShell = XtParent(w); Status status; Window *windowsReturn; int countReturn; while (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) { Window windows[2]; 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 { Window *windows = (Window *)XtMalloc((sizeof(Window))* (countReturn+1)); register int i; windows[0] = XtWindow(w); for (i=0; icore.width; cb.height = glw->core.height; XtCallCallbackList((Widget) glw, glw->glwDrawingArea.ginitCallback, &cb); } static void Redraw(GLwDrawingAreaWidget w, XEvent *event, Region region) { GLwDrawingAreaCallbackStruct cb; 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 we get a resize event before being realized, we can't handle it */ 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) { if (glw->glwDrawingArea.myList && glw->glwDrawingArea.attribList) XtFree ((XtPointer)glw->glwDrawingArea.attribList); if (glw->glwDrawingArea.myVisual && glw->glwDrawingArea.visualInfo) XFree ((XtPointer)glw->glwDrawingArea.visualInfo); /* if my colormap was installed, remove it */ if (glw->glwDrawingArea.installColormap) { Widget parentShell = XtParent(glw); Status status; Window *windowsReturn; int countReturn; register int i; /* find the parent shell */ while (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; icore.width; cb.height = glw->core.height; XtCallCallbackList ((Widget) glw, glw->glwDrawingArea.inputCallback, &cb); } #ifdef __GLX_MOTIF /* Provide a Motif-style create routine */ Widget GLwCreateMDrawingArea(Widget parent, char *name, ArgList arglist, Cardinal argcount) { return (XtCreateWidget (name, glwMDrawingAreaWidgetClass, parent, arglist, argcount)); } #endif