This is GLwDrawingArea.c in view mode; [Download] [Up]
/* GLwDrawingArea.c -- Mesa GL Widget for X11 Toolkit Programming Copyright (C) 1995, 1996 by Jeroen van der Zijp <jvz@cyberia.cfdrc.com> Thorsten Ohl <Thorsten.Ohl@Physik.TH-Darmstadt.de> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. $Id: GLwDrawingArea.c,v 1.24 1996/09/30 00:21:06 ohl Exp $ */ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <assert.h> #include <math.h> #include <float.h> #include <X11/X.h> #include <X11/Xlib.h> #include <X11/IntrinsicP.h> #include <X11/StringDefs.h> #include <X11/Shell.h> #ifdef __GLX_MOTIF #include <Xm/XmP.h> #include <Xm/PrimitiveP.h> #include <GL/GLwMDrawAP.h> #else #include <X11/CoreP.h> #include <GL/GLwDrawAP.h> #endif #include <X11/Xatom.h> #ifdef HAVE_XMU #include <X11/Xmu/StdCmap.h> /* for XmuLookupStandardColormap */ #endif #ifdef __GLX_MOTIF #define GLwDrawingAreaWidget GLwMDrawingAreaWidget #define GLwDrawingAreaClassRec GLwMDrawingAreaClassRec #define GLwDrawingAreaRec GLwMDrawingAreaRec #define glwDrawingAreaClassRec glwMDrawingAreaClassRec #define glwDrawingAreaWidgetClass glwMDrawingAreaWidgetClass #endif /* Actions */ static void glwInput (Widget w, XEvent * event, String * params, Cardinal * numParams); /* Methods */ static void ClassInitialize (void); 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); /* Translations */ static char defaultTranslations[] = "<KeyDown>: glwInput() \n\ <KeyUp>: glwInput() \n\ <BtnDown>: glwInput() \n\ <BtnUp>: glwInput() \n\ <BtnMotion>: glwInput() "; static XtActionsRec actions[] = { {"glwInput", (XtActionProc) glwInput}, /* key or mouse input */ }; static XtResource resources[] = { #undef offset #define offset(_field) XtOffset (GLwDrawingAreaWidget, glwDrawingArea._field) {GLwNattribList, GLwCAttribList, XtRPointer, sizeof (int *), offset (attribList), XtRImmediate, (caddr_t) NULL}, {GLwNvisualInfo, GLwCVisualInfo, GLwRVisualInfo, sizeof (XVisualInfo *), offset (visualInfo), XtRImmediate, (caddr_t) NULL}, {GLwNinstallColormap, GLwCInstallColormap, XtRBoolean, sizeof (Boolean), offset (installColormap), XtRImmediate, (caddr_t) True}, {GLwNallocateBackground, GLwNallocateOtherColors, XtRBoolean, sizeof (Boolean), offset (allocateBackground), XtRImmediate, (caddr_t) False}, {GLwNallocateOtherColors, GLwCAllocateColors, XtRBoolean, sizeof (Boolean), offset (allocateOtherColors), XtRImmediate, (caddr_t) False}, {GLwNinstallBackground, GLwCInstallBackground, XtRBoolean, sizeof (Boolean), offset (installBackground), XtRImmediate, (caddr_t) 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}, {GLwNbufferSize, GLwCBufferSize, XtRInt, sizeof (int), offset (bufferSize), XtRImmediate, (caddr_t) 0}, {GLwNlevel, GLwCLevel, XtRInt, sizeof (int), offset (level), XtRImmediate, (caddr_t) 0}, {GLwNrgba, GLwCRgba, XtRBoolean, sizeof (Boolean), offset (rgba), XtRImmediate, (caddr_t) False}, {GLwNdoublebuffer, GLwCDoublebuffer, XtRBoolean, sizeof (Boolean), offset (doublebuffer), XtRImmediate, (caddr_t) False}, {GLwNstereo, GLwCStereo, XtRBoolean, sizeof (Boolean), offset (stereo), XtRImmediate, (caddr_t) False}, {GLwNauxBuffers, GLwCAuxBuffers, XtRInt, sizeof (int), offset (auxBuffers), XtRImmediate, (caddr_t) 0}, {GLwNredSize, GLwCColorSize, XtRInt, sizeof (int), offset (redSize), XtRImmediate, (caddr_t) 1}, {GLwNgreenSize, GLwCColorSize, XtRInt, sizeof (int), offset (greenSize), XtRImmediate, (caddr_t) 1}, {GLwNblueSize, GLwCColorSize, XtRInt, sizeof (int), offset (blueSize), XtRImmediate, (caddr_t) 1}, {GLwNalphaSize, GLwCAlphaSize, XtRInt, sizeof (int), offset (alphaSize), XtRImmediate, (caddr_t) 0}, {GLwNdepthSize, GLwCDepthSize, XtRInt, sizeof (int), offset (depthSize), XtRImmediate, (caddr_t) 0}, {GLwNstencilSize, GLwCStencilSize, XtRInt, sizeof (int), offset (stencilSize), XtRImmediate, (caddr_t) 0}, {GLwNaccumRedSize, GLwCAccumColorSize, XtRInt, sizeof (int), offset (accumRedSize), XtRImmediate, (caddr_t) 0}, {GLwNaccumGreenSize, GLwCAccumColorSize, XtRInt, sizeof (int), offset (accumGreenSize), XtRImmediate, (caddr_t) 0}, {GLwNaccumBlueSize, GLwCAccumColorSize, XtRInt, sizeof (int), offset (accumBlueSize), XtRImmediate, (caddr_t) 0}, {GLwNaccumAlphaSize, GLwCAccumAlphaSize, XtRInt, sizeof (int), offset (accumAlphaSize), XtRImmediate, (caddr_t) 0}, #ifdef __GLX_MOTIF {XmNtraversalOn, XmCTraversalOn, XmRBoolean, sizeof (Boolean), XtOffset (GLwDrawingAreaWidget, primitive.traversal_on), XmRImmediate, (XtPointer) FALSE}, {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 {GLwNdebug, GLwCDebug, XtRBoolean, sizeof (Boolean), offset (debug), XtRImmediate, (caddr_t) False}, #undef offset }; GLwDrawingAreaClassRec glwDrawingAreaClassRec = { { /* Core fields */ #ifdef __GLX_MOTIF /* superclass */ (WidgetClass) & xmPrimitiveClassRec, /* class_name */ "GLwMDrawingArea", #else /* superclass */ (WidgetClass) & coreClassRec, /* class_name */ "GLwDrawingArea", #endif /* widget_size */ sizeof (GLwDrawingAreaRec), /* class_initialize */ ClassInitialize, /* 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 { /* XmPrimitive fields */ /* border_highlight */ (XtWidgetProc) _XtInherit, /* border_unhighlight */ (XtWidgetProc) _XtInherit, /* 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[256]; sprintf (buf, "%s: %s: %s\n", XtClass(w)->core_class.class_name, w->core.name, string); XtAppError (XtWidgetToApplicationContext (w), buf); } static void warning (Widget w, char *string) { char buf[256]; sprintf (buf, "%s: %s: %s\n", XtClass(w)->core_class.class_name, w->core.name, string); XtAppWarning (XtWidgetToApplicationContext (w), buf); } static Widget toplevel_widget (Widget w) { Widget p; for (p = XtParent (w); !XtIsShell (p); p = XtParent (p)) if (p == NULL) { p = w; error (w, "can't find shell widget"); } return p; } /* Create attribute list for passing to glxChooseVisual() from the ressources. */ #define ATTRIBLIST_SIZE 30 static void generate_attrib_list (GLwDrawingAreaPart *p) { int i = 0; p->attribList = (int *) XtCalloc (ATTRIBLIST_SIZE, sizeof (int)); p->attribList_allocated = True; p->attribList[i++] = GLX_BUFFER_SIZE; p->attribList[i++] = p->bufferSize; p->attribList[i++] = GLX_LEVEL; p->attribList[i++] = p->level; if (p->rgba) p->attribList[i++] = GLX_RGBA; if (p->doublebuffer) p->attribList[i++] = GLX_DOUBLEBUFFER; if (p->stereo) p->attribList[i++] = GLX_STEREO; p->attribList[i++] = GLX_AUX_BUFFERS; p->attribList[i++] = p->auxBuffers; p->attribList[i++] = GLX_RED_SIZE; p->attribList[i++] = p->redSize; p->attribList[i++] = GLX_GREEN_SIZE; p->attribList[i++] = p->greenSize; p->attribList[i++] = GLX_BLUE_SIZE; p->attribList[i++] = p->blueSize; p->attribList[i++] = GLX_ALPHA_SIZE; p->attribList[i++] = p->alphaSize; p->attribList[i++] = GLX_DEPTH_SIZE; p->attribList[i++] = p->depthSize; p->attribList[i++] = GLX_STENCIL_SIZE; p->attribList[i++] = p->stencilSize; p->attribList[i++] = GLX_ACCUM_RED_SIZE; p->attribList[i++] = p->accumRedSize; p->attribList[i++] = GLX_ACCUM_GREEN_SIZE; p->attribList[i++] = p->accumGreenSize; p->attribList[i++] = GLX_ACCUM_BLUE_SIZE; p->attribList[i++] = p->accumBlueSize; p->attribList[i++] = GLX_ACCUM_ALPHA_SIZE; p->attribList[i++] = p->accumAlphaSize; p->attribList[i++] = None; } #ifdef XmuLookupStandardColormap_OK static Colormap get_standard_rgb_map (Widget w, XVisualInfo *vi) { Colormap cmap = None; #ifdef HAVE_XMU Display *dpy = XtDisplay (w); int scr = XScreenNumberOfScreen (XtScreen (w)); if (XmuLookupStandardColormap (dpy, vi->screen, vi->visualid, vi->depth, XA_RGB_DEFAULT_MAP, False, True)) { XStandardColormap *std_cmaps; int i, num_cmaps; if (XGetRGBColormaps (dpy, RootWindow (dpy, scr), &std_cmaps, &num_cmaps, XA_RGB_DEFAULT_MAP)) { for (i = 0; i < num_cmaps; i++) if (std_cmaps[i].visualid == vi->visualid) { cmap = std_cmaps[i].colormap; break; } XFree (std_cmaps); } } #endif /* HAVE_XMU */ return cmap; } #endif /* XmuLookupStandardColormap_OK */ #define glw_cmaps glwDrawingAreaClassRec.glwDrawingArea_class.colormaps static Colormap lookup_colormap (Widget w, XVisualInfo *vi, int alloc) { Display *dpy; int scr; Colormap cmap; int i; LOG (w); dpy = XtDisplay (w); scr = XScreenNumberOfScreen (XtScreen (w)); cmap = None; #ifdef DEBUG if (GLwDebug(w)) fprintf (stderr, "looking up colormap for visual id #%ld on display #%p ... ", vi->visualid, dpy); #endif assert (glw_cmaps.entries); for (i = 0; i < glw_cmaps.next_entry; i++) if ((glw_cmaps.entries[i].dpy == dpy) && (glw_cmaps.entries[i].vid == vi->visualid)) { #ifdef DEBUG if (GLwDebug(w)) fprintf (stderr, "found #%ld\n", glw_cmaps.entries[i].cmap); #endif return glw_cmaps.entries[i].cmap; } #ifdef XmuLookupStandardColormap_OK /* Commented out as of version 1.2.8 since Sun-SGI display causes a weird problem. Probably a bug in Sun's XmuLookupStandardColormap(). */ if ((vi->class == TrueColor) || (vi->class == DirectColor)) cmap = get_standard_rgb_map (w, vi); /* I had put this code (which is inspired by glut) in for a reason because I had experienced problems with 8 bit TrueColor visuals. Now I can't reproduce these problem anymore. I'll leave it in as inactive code, in case somebody can reproduce the old problems. */ #endif /* Code to look for HP Color Recovery Atom and colormap contributed by Jean-Luc Daems (jld@star.be) on Feb 23, 1996. */ if (cmap == None) { Atom hp_cr_maps = XInternAtom(dpy,"_HP_RGB_SMOOTH_MAP_LIST",True) ; if (hp_cr_maps) { XStandardColormap* colmaps = 0; int nrColmaps = 0; int i; XGetRGBColormaps( dpy, RootWindow(dpy, scr), &colmaps, &nrColmaps, hp_cr_maps ); for (i=0; i<nrColmaps; i++) { if (colmaps[i].visualid == vi->visual->visualid) { cmap = colmaps[i].colormap; break; } } } } if (cmap == None) cmap = XCreateColormap (dpy, RootWindow (dpy, scr), vi->visual, AllocNone); if (!cmap) error (w, "can't get a colormap"); if (glw_cmaps.next_entry >= glw_cmaps.allocated_entries) { glw_cmaps.allocated_entries += 10; glw_cmaps.entries = (struct cmap_cache_entry *) XtRealloc ((char *) glw_cmaps.entries, glw_cmaps.allocated_entries * sizeof (struct cmap_cache_entry)); } i = glw_cmaps.next_entry++; glw_cmaps.entries[i].dpy = dpy; glw_cmaps.entries[i].vid = vi->visualid; glw_cmaps.entries[i].cmap = cmap; #ifdef DEBUG if (GLwDebug(w)) fprintf (stderr, "allocated new #%ld\n", cmap); #endif return cmap; } /* Inform the window manager that the widget W's window needs a special colormap by setting the WM_COLORMAP_WINDOWS property on the top level shell. FIXME: we should use XGetWMColormapWindows () to check for other windows and add our window to this list instead of overwriting. */ static void post_colormap (Widget w) { Widget top = toplevel_widget (w); Window wlist[2]; wlist[0] = XtWindow(w); wlist[1] = XtWindow(top); if (!XSetWMColormapWindows (XtDisplay(top), XtWindow(top), wlist, 2)) warning (w, "can't post colormap"); } /* Widget methods. */ /* Initialize this widget class. Currently we just allocate the first chunk of memory for the colormap cache. */ static void ClassInitialize (void) { /* two's a crowd ... (for most applications) */ glw_cmaps.allocated_entries = 2; glw_cmaps.next_entry = 0; glw_cmaps.entries = (struct cmap_cache_entry *) XtMalloc (glw_cmaps.allocated_entries * sizeof (struct cmap_cache_entry)); } /* Initialize a widget instance. Here's where we do the colormap dance. */ static void Initialize (GLwDrawingAreaWidget req, GLwDrawingAreaWidget new, ArgList args, Cardinal *num_args) { Display *dpy; int scr; XVisualInfo *vi; LOG (new); dpy = XtDisplay (new); scr = XScreenNumberOfScreen (XtScreen (new)); if (req->core.width == 0) new->core.width = 100; if (req->core.height == 0) new->core.width = 100; new->glwDrawingArea.attribList_allocated = False; new->glwDrawingArea.visualInfo_allocated = False; vi = new->glwDrawingArea.visualInfo; /* If there's no visual in the resources, we have to select our own, based on the attribute list or the other resources. */ if (vi == NULL) { /* If the list of attribues is not defined in the resources, we have to build one from the other resources. */ if (new->glwDrawingArea.attribList == NULL) generate_attrib_list (&new->glwDrawingArea); /* Select the visual and remember it. */ vi = glXChooseVisual (dpy, scr, new->glwDrawingArea.attribList); if (!vi) error ((Widget) new, "can't get a visual"); new->glwDrawingArea.visualInfo = vi; new->glwDrawingArea.visualInfo_allocated = True; } new->core.depth = vi->depth; /* If we're rendering in the default visual in color-index mode, we continue to use the default map. This is the most economical approach. In RGBA mode we try to use a standard RGB map for TrueColor and DirectColor visuals. If this is not available and for all other visuals, we allocate a fresh colormap. */ if (!new->glwDrawingArea.rgba && (vi->visualid == XVisualIDFromVisual (DefaultVisual (dpy, scr)))) new->core.colormap = DefaultColormap (dpy, scr); else new->core.colormap = lookup_colormap ((Widget) new, vi, AllocNone); } /* Realize a widget. That's trivial, we just create the window with the appropriate visual and call the callback functions. */ static void Realize (Widget w, Mask *mask, XSetWindowAttributes *attr) { GLwDrawingAreaWidget glw; Display *dpy; int scr; GLwDrawingAreaCallbackStruct cb; LOG (w); glw = (GLwDrawingAreaWidget) w; dpy = XtDisplay (w); scr = XScreenNumberOfScreen (XtScreen (w)); /* Create the window. */ attr->colormap = w->core.colormap; attr->event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | ButtonMotionMask | ExposureMask | StructureNotifyMask; attr->border_pixel = BlackPixel (dpy, scr); attr->background_pixel = BlackPixel (dpy, scr); attr->backing_store = NotUseful; *mask = CWColormap | CWEventMask | CWBorderPixel | CWBackPixel | CWBackingStore; XtCreateWindow (w, (unsigned int) InputOutput, glw->glwDrawingArea.visualInfo->visual, *mask, attr); /* Install the colormap if requested. */ if (glw->glwDrawingArea.installColormap) post_colormap (w); /* Invoke callback to initialize. */ cb.reason = GLwCR_GINIT; cb.event = NULL; cb.width = glw->core.width; cb.height = glw->core.height; XtCallCallbackList ((Widget) glw, glw->glwDrawingArea.ginitCallback, &cb); } /* Invoke expose callbacks to redraw screen */ static void Redraw (GLwDrawingAreaWidget w, XEvent * event, Region region) { GLwDrawingAreaCallbackStruct cb; LOG (w); /* Ignore while not yet realized. */ 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); } /* Invoke resize callbacks */ static void Resize (GLwDrawingAreaWidget glw) { GLwDrawingAreaCallbackStruct cb; LOG (glw); /* Ignore while not yet realized. */ 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); } /* Window destroy handling. FIXME: shouldn't we remove the WM_COLORMAP_WINDOWS property from the toplevel shell? */ static void Destroy (GLwDrawingAreaWidget glw) { LOG (glw); XtRemoveAllCallbacks ((Widget) glw, GLwNinputCallback); XtRemoveAllCallbacks ((Widget) glw, GLwNresizeCallback); XtRemoveAllCallbacks ((Widget) glw, GLwNexposeCallback); if (glw->glwDrawingArea.attribList_allocated) { XtFree ((char *)glw->glwDrawingArea.attribList); glw->glwDrawingArea.attribList_allocated = False; } if (glw->glwDrawingArea.visualInfo_allocated) { XtFree ((char *)glw->glwDrawingArea.visualInfo); glw->glwDrawingArea.visualInfo_allocated = False; } } /* Action routine for keyboard and mouse events */ static void glwInput (Widget w, XEvent * event, String * params, Cardinal * numParams) { GLwDrawingAreaCallbackStruct cb; GLwDrawingAreaWidget glw = (GLwDrawingAreaWidget) w; LOG (w); cb.reason = GLwCR_INPUT; cb.event = event; cb.width = glw->core.width; cb.height = glw->core.height; XtCallCallbackList ((Widget) glw, glw->glwDrawingArea.inputCallback, &cb); } /* The End. */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.