/* * * Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 * Lesser General Public License for more details. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like. Any license provided herein, whether implied or * otherwise, applies only to this software file. Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA 94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ * */ /* * Copyright (C) 1990-93 Silicon Graphics, Inc. * _______________________________________________________________________ ______________ S I L I C O N G R A P H I C S I N C . ____________ | | $Revision: 1.2 $ | | Classes: | SoXtGLWidget | | Author(s): Alain Dumesny, David Mott | ______________ S I L I C O N G R A P H I C S I N C . ____________ _______________________________________________________________________ */ #include #include #ifdef __sgi #include #endif #include #include #include #include "SoGLwMDrawA.h" #include #include #include #include /* * macros */ #define SET_BIT(mode, mask, flag) \ if (flag) mode |= mask; \ else mode &= ~mask; #define SCREEN(w) XScreenNumberOfScreen( XtScreen(w) ) //////////////////////////////////////////////////////////////////////// // // Each display has a list of GLXContext to be shared across all glx windows typedef struct _SoContextListDisplayPair { Display *display; int screen; SbPList *contextList; } SoContextListDisplayPair; // This class finds a context list for the passed display. // Contexts can then be searched for, added, and removed from that list. class SoContextListKeeper : private SbPList { public: SoContextListKeeper() {} SbPList *find(Display *d, int screen); int whichDisplay(GLXContext ctx); }; SbPList * SoContextListKeeper::find(Display *d, int screen) { SoContextListDisplayPair *p = NULL; // Search for a context list associated with Display for (int i = 0; i < getLength(); i++) { SoContextListDisplayPair *p = (SoContextListDisplayPair *)this->get(i); if (p->display == d && p->screen == screen ) { return p->contextList; } } // If we got to here, we didn't find it. Create one. p = new SoContextListDisplayPair; p->display = d; p->screen = screen; p->contextList = new SbPList; append((void *) p); return p->contextList; } // Returns unique integers for contexts on different displays. Used // to determine when display lists can/can't be shared (display lists // are shared between contexts on the same display). int SoContextListKeeper::whichDisplay(GLXContext ctx) { for (int i = 0; i < getLength(); i++) { SoContextListDisplayPair *p = (SoContextListDisplayPair *)(*this)[i]; for (int j = 0; j < p->contextList->getLength(); j++) { if (p->contextList->get(j) == (const void *)ctx) return i; } } #ifdef DEBUG SoDebugError::post("SoContextListKeeper::whichList", "Context not found!"); #endif return -1; } // When you need to find a context list, do this: // SbPList *contextList = contextListKeeper.find(XtDisplay(myWidget), SCREEN(myWidget)); static SoContextListKeeper contextListKeeper; // //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// // // Constructor // SoXtGLWidget::SoXtGLWidget( Widget parent, const char *name, SbBool buildInsideParent, int modes, SbBool buildNow) : SoXtComponent(parent, name, buildInsideParent) // //////////////////////////////////////////////////////////////////////// { // window related variables mgrWidget = NULL; singleBufferWidget = doubleBufferWidget = overlayWidget = NULL; ctxNormal = ctxOverlay = ctxSingle = ctxDouble = 0; colorMap = overlayColorMap = 0; glModes = modes; windowResized = FALSE; glxSize.setValue(0, 0); borderSize = 0; waitForExpose = TRUE; drawToFrontBuffer = TRUE; // used by RA to draw new scenes to front buffer enableDrawToFrontBuffer = TRUE; // // window attribute list // int n = 0; attribList = new int[14]; // insert no-op GLX_USE_GL for double/stereo if they are off since those // change dynamically and it is easier to set them again than it is // to insert them. attribList[n++] = (glModes & SO_GLX_DOUBLE) ? GLX_DOUBLEBUFFER : GLX_USE_GL; attribList[n++] = (glModes & SO_GLX_STEREO) ? GLX_STEREO : GLX_USE_GL; if (glModes & SO_GLX_RGB) { // This makes sure we get the maximum buffer configuration // by showing interest the number of bits attribList[n++] = GLX_RGBA; attribList[n++] = GLX_RED_SIZE; attribList[n++] = 1; attribList[n++] = GLX_GREEN_SIZE; attribList[n++] = 1; attribList[n++] = GLX_BLUE_SIZE; attribList[n++] = 1; } if (glModes & SO_GLX_ZBUFFER) { attribList[n++] = GLX_DEPTH_SIZE; attribList[n++] = 1; } attribList[n++] = None; // Build the widget tree, and let SoXtComponent know about our base widget. if (buildNow) setBaseWidget(buildWidget(getParentWidget())); } //////////////////////////////////////////////////////////////////////// // // virtual destructor // SoXtGLWidget::~SoXtGLWidget() // //////////////////////////////////////////////////////////////////////// { delete [] attribList; // delete the GLX widgets (free the context and the visual too) if (doubleBufferWidget) destroyGLXWidget(doubleBufferWidget, ctxDouble, TRUE); if (singleBufferWidget) destroyGLXWidget(singleBufferWidget, ctxSingle, TRUE); if (overlayWidget) destroyGLXWidget(overlayWidget, ctxOverlay, FALSE); } //////////////////////////////////////////////////////////////////////// // // Description: // sets the normal window visual // // Use: public void SoXtGLWidget::setNormalVisual(XVisualInfo *newvis) // //////////////////////////////////////////////////////////////////////// { if (! newvis) return; Display *dpy = XtDisplay(mgrWidget); int val; // make sure visual supports OpenGL glXGetConfig(dpy, newvis, GLX_USE_GL, &val); if (! val) { #ifdef DEBUG SoDebugError::post("SoXtGLWidget::setNormalVisual", "visual does not support OpenGL."); #endif return; } // make sure this visual is for normal frame buffer glXGetConfig(dpy, newvis, GLX_LEVEL, &val); if (val != 0) { #ifdef DEBUG SoDebugError::post("SoXtGLWidget::setNormalVisual", "visual is not for the normal frame buffer."); #endif return; } // Make a copy of the XVisualInfo structure - we don't want to rely // on a pointer which the programmer can delete at any time. XVisualInfo *vis = (XVisualInfo *) XtMalloc(sizeof(XVisualInfo)); bcopy(newvis, vis, sizeof(XVisualInfo)); // // build a new attribute list from the given visual // to be used later when we toggle single/double and want to // keep the other settings the same. // int newAttribList[30], num=0; glXGetConfig(dpy, vis, GLX_DOUBLEBUFFER, &val); newAttribList[num++] = val ? GLX_DOUBLEBUFFER : GLX_USE_GL; SET_BIT(glModes, SO_GLX_DOUBLE, val); glXGetConfig(dpy, vis, GLX_STEREO, &val); newAttribList[num++] = val ? GLX_STEREO : GLX_USE_GL; SET_BIT(glModes, SO_GLX_STEREO, val); glXGetConfig(dpy, vis, GLX_RGBA, &val); SET_BIT(glModes, SO_GLX_RGB, val); if (val) { // ??? should we check what the current RGBA sizes are ? newAttribList[num++] = GLX_RGBA; newAttribList[num++] = GLX_RED_SIZE; newAttribList[num++] = 1; newAttribList[num++] = GLX_GREEN_SIZE; newAttribList[num++] = 1; newAttribList[num++] = GLX_BLUE_SIZE; newAttribList[num++] = 1; } glXGetConfig(dpy, vis, GLX_AUX_BUFFERS, &val); if (val) { newAttribList[num++] = GLX_AUX_BUFFERS; newAttribList[num++] = val; } glXGetConfig(dpy, vis, GLX_DEPTH_SIZE, &val); if (val) { newAttribList[num++] = GLX_DEPTH_SIZE; newAttribList[num++] = 1; // ??? should we use the size ? } glXGetConfig(dpy, vis, GLX_STENCIL_SIZE, &val); if (val) { newAttribList[num++] = GLX_STENCIL_SIZE; newAttribList[num++] = 1; // ??? should we use the size ? } // ??? only check the RED accumulation ? glXGetConfig(dpy, vis, GLX_ACCUM_RED_SIZE, &val); if (val) { newAttribList[num++] = GLX_ACCUM_RED_SIZE; newAttribList[num++] = 1; // ??? should we use the size ? newAttribList[num++] = GLX_ACCUM_GREEN_SIZE; newAttribList[num++] = 1; newAttribList[num++] = GLX_ACCUM_BLUE_SIZE; newAttribList[num++] = 1; } // copy the new attributes over delete [] attribList; attribList = new int[num+1]; for (int i=0; ifind(ctx); if (index != -1) contextList->remove(index); // also delete the visual XVisualInfo *vis; XtVaGetValues(w, SoGLwNvisualInfo, &vis, NULL); if (vis != NULL) XFree(vis); XtVaSetValues(w, SoGLwNvisualInfo, NULL, NULL); } else // else add a destroy callback to delete the visual later // because the widget will be realized BEFORE the widget // gets to actually be destroyed (calling XtDestroyWidget() // only marks the widget to later be deleted - see bug 238440) XtAddCallback (w, XmNdestroyCallback, glxWidgetDestroyCB, (XtPointer) NULL); // remove any callbacks we added to this widget // (we need to do this to prevent the ginitCB to be called if we // delete this widget before the component was realized - see bug 238440) if (normalWindow) { XtRemoveCallback(w, SoGLwNginitCallback, (XtCallbackProc) SoXtGLWidget::ginitCB, (XtPointer) this); XtRemoveCallback(w, SoGLwNresizeCallback, (XtCallbackProc) SoXtGLWidget::resizeCB, (XtPointer) this); XtRemoveCallback(w, SoGLwNexposeCallback, (XtCallbackProc) SoXtGLWidget::exposeCB, (XtPointer) this); } else { XtRemoveCallback(w, SoGLwNginitCallback, (XtCallbackProc) SoXtGLWidget::overlayGinitCB, (XtPointer) this); XtRemoveCallback(w, SoGLwNexposeCallback, (XtCallbackProc) SoXtGLWidget::overlayExposeCB, (XtPointer) this); } // delete the widget and reset the passed pointers XtDestroyWidget(w); w = NULL; ctx = 0; } //////////////////////////////////////////////////////////////////////// // // Description: // destroys the current set of windows (called when visual changes) // This doesn't affect the overly window thought. // // Use: private void SoXtGLWidget::destroyNormalWindows() // //////////////////////////////////////////////////////////////////////// { // let subclasses remove stuff on the old widget widgetChanged(NULL); if (doubleBufferWidget) destroyGLXWidget(doubleBufferWidget, ctxDouble, TRUE); if (singleBufferWidget) destroyGLXWidget(singleBufferWidget, ctxSingle, TRUE); // reset the other local normal window vars (don't change the overlay) ctxNormal = 0; colorMap = 0; } //////////////////////////////////////////////////////////////////////// // // Description: // This builds a form around the GLX widget. Subclasses should // register their own event interest. // // Use: protected // Widget SoXtGLWidget::buildWidget(Widget parent) // //////////////////////////////////////////////////////////////////////// { // // build a top level form to hold the GLX widgets (single/double/overlay) // Arg args[8]; int n = 0; XtSetArg(args[n], XmNshadowType, XmSHADOW_IN); n++; XtSetArg(args[n], XmNshadowThickness, borderSize); n++; // pick an initial size if set SbVec2s size = (glxSize[0] && glxSize[1]) ? glxSize : getSize(); if (size[0] && size[1]) { XtSetArg(args[n], XtNwidth, size[0] + 2*borderSize); n++; XtSetArg(args[n], XtNheight, size[1] + 2*borderSize); n++; } // ??? don't listen to resize request by children (the parent will // ??? force their size). This will prevent the RenderArea // ??? to pop to 400x400 size (default) after the user set an explicit // ??? smaller size. XtSetArg(args[n], XmNresizePolicy, XmRESIZE_NONE); n++; mgrWidget = XtCreateWidget(getWidgetName(), xmFormWidgetClass, parent, args, n); buildNormalGLXWidget(); if (glModes & SO_GLX_OVERLAY) // make this the top window buildOverlayGLXWidget(); return mgrWidget; } //////////////////////////////////////////////////////////////////////// // // Description: // This builds a GLX widget of the correct current type. // // Use: protected void SoXtGLWidget::buildNormalGLXWidget(XVisualInfo *vis) // //////////////////////////////////////////////////////////////////////// { // build the visual from the attribute list if necessary if (! vis) { vis = glXChooseVisual(XtDisplay(mgrWidget), XScreenNumberOfScreen(XtScreen(mgrWidget)), attribList); if (! vis) { #ifdef DEBUG SoDebugError::post("SoXtGLWidget::buildNormalGLXWidget", "could not create visual"); #endif return; } } int val; glXGetConfig(XtDisplay(mgrWidget), vis, GLX_DOUBLEBUFFER, &val); SET_BIT(glModes, SO_GLX_DOUBLE, val); // // Build the GLX widget // Arg args[12]; int n = 0; XtSetArg(args[n], SoGLwNvisualInfo, vis); n++; // enables XmProcessTraversal() to be called (done in RA) XtSetArg(args[n], XmNtraversalOn, TRUE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, borderSize); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightOffset, borderSize); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopOffset, borderSize); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomOffset, borderSize); n++; Widget glx = XtCreateWidget("GlxWidget", SoglwMDrawingAreaWidgetClass, mgrWidget, args, n); // // Add GLX specific callbacks // XtAddCallback(glx, SoGLwNginitCallback, (XtCallbackProc) SoXtGLWidget::ginitCB, (XtPointer) this); XtAddCallback(glx, SoGLwNresizeCallback, (XtCallbackProc) SoXtGLWidget::resizeCB, (XtPointer) this); XtAddCallback(glx, SoGLwNexposeCallback, (XtCallbackProc) SoXtGLWidget::exposeCB, (XtPointer) this); // enables us to add the event handler on the parent instead // XtUninstallTranslations(glx); // assign the right widget var and manage widget if (isDoubleBuffer()) doubleBufferWidget = glx; else singleBufferWidget = glx; XtManageChild(glx); // make sure overlay window is on top if (overlayWidget && XtWindow(overlayWidget)) XRaiseWindow(XtDisplay(overlayWidget), XtWindow(overlayWidget)); // prevent a redraw a redraw from happening until we receive an // expose event - this will prevent too many redraws from happening // if the scene graph also changes at the same time. waitForExpose = TRUE; } //////////////////////////////////////////////////////////////////////// // // Description: // This builds the overly GLX widget (which is static) // // Use: protected void SoXtGLWidget::buildOverlayGLXWidget(XVisualInfo *vis) // //////////////////////////////////////////////////////////////////////// { #ifdef __sgi // build the visual from the attribute list if necessary if (! vis) { // // make sure the visual can be created, else don't built the overlay // widget (subclasses won't assume it is always built) // int n = 0, list[5]; list[n++] = GLX_LEVEL; // overlay planes list[n++] = 1; // overlay planes list[n++] = GLX_BUFFER_SIZE; // get at least 2 bits list[n++] = 2; list[n++] = None; vis = glXChooseVisual(XtDisplay(mgrWidget), XScreenNumberOfScreen(XtScreen(mgrWidget)), list); if (! vis) { #ifdef DEBUG SoDebugError::post("SoXtGLWidget::buildOverlayGLXWidget", "could not create overlay visual"); #endif return; } } Arg args[12]; int n = 0; XtSetArg(args[n], SoGLwNvisualInfo, vis); n++; // enables XmProcessTraversal() to be called (done in RA) XtSetArg(args[n], XmNtraversalOn, TRUE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, borderSize); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightOffset, borderSize); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopOffset, borderSize); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomOffset, borderSize); n++; overlayWidget = XtCreateWidget("OverlayGLX", SoglwMDrawingAreaWidgetClass, mgrWidget, args, n); // // Add GLX specific callbacks // XtAddCallback(overlayWidget, SoGLwNginitCallback, (XtCallbackProc) SoXtGLWidget::overlayGinitCB, (XtPointer) this); XtAddCallback(overlayWidget, SoGLwNexposeCallback, (XtCallbackProc) SoXtGLWidget::overlayExposeCB, (XtPointer) this); // enables us to add the event handler on the parent instead // XtUninstallTranslations(overlayWidget); XtManageChild(overlayWidget); #else overlayWidget = 0; #endif } //////////////////////////////////////////////////////////////////////// // // Description: // turns border on/off // // Use: public void SoXtGLWidget::setBorder(SbBool flag) // //////////////////////////////////////////////////////////////////////// { if (flag == isBorder()) return; // set the border size and update the widgets borderSize = flag ? 2 : 0; Arg args[4]; int n = 0; XtSetArg(args[n], XmNleftOffset, borderSize); n++; XtSetArg(args[n], XmNrightOffset, borderSize); n++; XtSetArg(args[n], XmNtopOffset, borderSize); n++; XtSetArg(args[n], XmNbottomOffset, borderSize); n++; if (doubleBufferWidget) XtSetValues(doubleBufferWidget, args, n); if (singleBufferWidget) XtSetValues(singleBufferWidget, args, n); if (overlayWidget) XtSetValues(overlayWidget, args, n); } //////////////////////////////////////////////////////////////////////// // // Description: // enables/disabled the drawToFrontBuffer functionality // // Use: public void SoXtGLWidget::setDrawToFrontBufferEnable(SbBool flag) // //////////////////////////////////////////////////////////////////////// { enableDrawToFrontBuffer = flag; // clear the flag is disabled if (! enableDrawToFrontBuffer) drawToFrontBuffer = FALSE; } //////////////////////////////////////////////////////////////////////// // // Description: // sets the size of the glx widgets // // Use: protected void SoXtGLWidget::setGlxSize(SbVec2s newSize) // //////////////////////////////////////////////////////////////////////// { if (newSize == glxSize) return; // now set the container widget size (children will resize automatically) if (mgrWidget) XtVaSetValues(mgrWidget, XtNwidth, glxSize[0] + 2 * borderSize, XtNheight, glxSize[1] + 2 * borderSize, NULL); // else we havn't built yet, so cache this initial build size else glxSize = newSize; } Window SoXtGLWidget::getNormalWindow() { return getNormalWidget() ? XtWindow(getNormalWidget()) : 0; } Window SoXtGLWidget::getOverlayWindow() { return getOverlayWidget() ? XtWindow(getOverlayWidget()) : 0; } // //////////////////////////////////////////////////////////////////////// // static callbacks stubs //////////////////////////////////////////////////////////////////////// // void SoXtGLWidget::eventHandler(Widget w, SoXtGLWidget *p, XAnyEvent *xe, Boolean *) { // // check and remove any other motion events in the queue for // that same window (compress the event) - don't use // XCheckTypedWindowEvent() because we DON't want to remove // all mouse motion events in the queue (even the ones we // get after other events) - instead only remove the next event // if it is a mouse event. // if (xe->type == MotionNotify) { //XMotionEvent *me = (XMotionEvent *)xe; //printf("0 %d\n", me->time); //int i=1; Display *display = XtDisplay(w); XEvent event, motion; SbBool valid = FALSE; while (XEventsQueued(display, QueuedAlready)) { XPeekEvent(display, &event); if (event.type == MotionNotify) { XNextEvent(display, &motion); valid = TRUE; //me = (XMotionEvent *) &motion; //printf("%d %d\n", i++, me->time); } else if (event.type == NoExpose) // toss it out - for some reason // those events are being generated // in the middle of motion (for the color picker) // and we need to discard them out... XNextEvent(display, &event); else { //printf("type %d\n", event.type); break; } } if (valid) p->processEvent((XAnyEvent *) &motion); // latest motion else p->processEvent(xe); // original motion return; } p->processEvent(xe); } void SoXtGLWidget::ginitCB(Widget glx, SoXtGLWidget *p, XtPointer pt) { // set the initial size of the glx widget SoGLwDrawingAreaCallbackStruct *data = (SoGLwDrawingAreaCallbackStruct *) pt; p->glxSize.setValue(data->width, data->height); // // create a GLX context, and make this the current window, but before // make sure that we don't already have a valid context (because // ginitCB() will be called every time the widget is realized, not just // the first time). // GLXContext ctx = p->isDoubleBuffer() ? p->ctxDouble : p->ctxSingle; if (ctx == 0) { SbPList *contextList = contextListKeeper.find(XtDisplay(glx), SCREEN(glx)); if (contextList->getLength()) ctx = (GLXContext) (*contextList)[0]; XVisualInfo *vis; XtVaGetValues(glx, SoGLwNvisualInfo, &vis, NULL); ctx = glXCreateContext(XtDisplay(glx), vis, ctx, GL_TRUE); contextList->append(ctx); if (glx == p->doubleBufferWidget) p->ctxDouble = ctx; else p->ctxSingle = ctx; } p->ctxNormal = ctx; glXMakeCurrent(XtDisplay(glx), XtWindow(glx), ctx); // enable zbuffer if this visual supports it.... if (p->glModes & SO_GLX_ZBUFFER) glEnable(GL_DEPTH_TEST); // // get the normal window color map, and allocate every colors // as read/write. // // Note: this only needs to be done once since the color map is // shared between widgets. // static Colormap previousMap = 0; if (! p->isRGBMode()) { XtVaGetValues(glx, XmNcolormap, &p->colorMap, NULL); if (p->colorMap != previousMap) { unsigned long plane_mask[1]; // System long XVisualInfo *vis; XtVaGetValues(glx, SoGLwNvisualInfo, &vis, NULL); int ncolors = vis->colormap_size; Pixel *pixel = (Pixel *) XtMalloc(ncolors*sizeof(Pixel)); int result = XAllocColorCells(XtDisplay(glx), p->colorMap, True, plane_mask, 0, pixel, ncolors); XtFree((char *) pixel); previousMap = p->colorMap; } } // let subclasses know we changed widget p->widgetChanged(glx); // forces sizeChanged() to be at least called once p->windowResized = TRUE; // finally call subclass routine p->initGraphic(); // make sure overlay window is on top if (p->overlayWidget && XtWindow(p->overlayWidget)) XRaiseWindow(XtDisplay(p->overlayWidget), XtWindow(p->overlayWidget)); } void SoXtGLWidget::overlayGinitCB(Widget glx, SoXtGLWidget *p, XtPointer) { // // create a GLX context, and make this the current window, but before // make sure that we don't already have a valid context (because // overlayGinitCB() will be called every time the widget is realized, // not just the first time). // if (p->ctxOverlay == 0) { GLXContext ctx = 0; SbPList *contextList = contextListKeeper.find(XtDisplay(glx),SCREEN(glx)); if (contextList->getLength()) ctx = (GLXContext) (*contextList)[0]; XVisualInfo *vis; XtVaGetValues(glx, SoGLwNvisualInfo, &vis, NULL); p->ctxOverlay = glXCreateContext(XtDisplay(glx), vis, ctx, GL_TRUE); contextList->append(p->ctxOverlay); } glXMakeCurrent(XtDisplay(glx), XtWindow(glx), p->ctxOverlay); // // get the overlay color map, and allocate every colors // as read/write except transparency color 0. // // Note: this only needs to be done once since the color map is // shared between overlay widgets. // static Colormap previousMap = 0; XtVaGetValues(glx, XmNcolormap, &p->overlayColorMap, NULL); if (p->overlayColorMap != previousMap) { unsigned long plane_mask[1]; // System long XVisualInfo *vis; XtVaGetValues(glx, SoGLwNvisualInfo, &vis, NULL); int ncolors = vis->colormap_size - 1; // one less due to transparency Pixel *pixel = (Pixel *) XtMalloc(ncolors*sizeof(Pixel)); int result = XAllocColorCells(XtDisplay(glx), p->overlayColorMap, True, plane_mask, 0, pixel, ncolors); XtFree((char *) pixel); previousMap = p->overlayColorMap; } // forces sizeChanged() to be at least called once p->windowResized = TRUE; // finally call subclass routine p->initOverlayGraphic(); } void SoXtGLWidget::exposeCB(Widget w, SoXtGLWidget *p, XtPointer) { // check and remove any other expose events in the queue for // that same window (compress expose events). XEvent event; while (XCheckTypedWindowEvent(XtDisplay(w), XtWindow(w), Expose, &event)) ; // check if subclasses sizeChanged() routine needs to be called. if (p->windowResized) { p->sizeChanged(p->glxSize); p->windowResized = FALSE; } // clear this flag now that we have an expose event p->waitForExpose = FALSE; // on expose, draw the first image to the front buffer since we // might have garbadge in the window anyway.... if (p->enableDrawToFrontBuffer) p->drawToFrontBuffer = TRUE; p->redraw(); } void SoXtGLWidget::overlayExposeCB(Widget w, SoXtGLWidget *p, XtPointer) { // check and remove any other expose events in the queue for // that same window (compress expose events). XEvent event; while (XCheckTypedWindowEvent(XtDisplay(w), XtWindow(w), Expose, &event)) ; // check if subclasses sizeChanged() routine needs to be called. if (p->windowResized) { p->sizeChanged(p->glxSize); p->windowResized = FALSE; } p->redrawOverlay(); } void SoXtGLWidget::resizeCB(Widget, SoXtGLWidget *p, XtPointer pt) { // set the new glx window size SoGLwDrawingAreaCallbackStruct *data = (SoGLwDrawingAreaCallbackStruct *) pt; p->glxSize.setValue(data->width, data->height); // ??? only set the flag right now instead of calling sizeChanged() // ??? because the window hasn't been mapped to it's new size yet // ??? (wait for expose event). p->windowResized = TRUE; } // //////////////////////////////////////////////////////////////////////// // dummy virtual functions //////////////////////////////////////////////////////////////////////// // void SoXtGLWidget::redrawOverlay() {} void SoXtGLWidget::processEvent(XAnyEvent *) {} void SoXtGLWidget::initGraphic() {} void SoXtGLWidget::initOverlayGraphic() {} void SoXtGLWidget::sizeChanged(const SbVec2s &) {} void SoXtGLWidget::widgetChanged(Widget) {}