/* * * 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.5 $ | | Classes: | SoXtRenderArea | | Author(s): David Mott, Alain Dumesny | ______________ S I L I C O N G R A P H I C S I N C . ____________ _______________________________________________________________________ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static char *thisClassName = "SoXtRenderArea"; //////////////////////////////////////////////////////////////////////// // // Public constructor - build the widget right now // SoXtRenderArea::SoXtRenderArea( Widget parent, const char *name, SbBool buildInsideParent, SbBool getMouseInput, SbBool getKeyboardInput) : SoXtGLWidget( parent, name, buildInsideParent, SO_GLX_RGB | SO_GLX_DOUBLE | SO_GLX_ZBUFFER | SO_GLX_OVERLAY, FALSE) // tell GLWidget not to build just yet // //////////////////////////////////////////////////////////////////////// { // In this case, render area is what the app wants, so buildNow = TRUE constructorCommon(getMouseInput, getKeyboardInput, TRUE); } //////////////////////////////////////////////////////////////////////// // // SoEXTENDER constructor - the subclass tells us whether to build or not // SoXtRenderArea::SoXtRenderArea( Widget parent, const char *name, SbBool buildInsideParent, SbBool getMouseInput, SbBool getKeyboardInput, SbBool buildNow) : SoXtGLWidget( parent, name, buildInsideParent, SO_GLX_RGB | SO_GLX_DOUBLE | SO_GLX_ZBUFFER | SO_GLX_OVERLAY, FALSE) // tell GLWidget not to build just yet // //////////////////////////////////////////////////////////////////////// { // In this case, render area may be what the app wants, // or it may want a subclass of render area. Pass along buildNow // as it was passed to us. constructorCommon(getMouseInput, getKeyboardInput, buildNow); } //////////////////////////////////////////////////////////////////////// // // Called by the constructors // // private // void SoXtRenderArea::constructorCommon( SbBool getMouseInput, SbBool getKeyboardInput, SbBool buildNow) // //////////////////////////////////////////////////////////////////////// { addVisibilityChangeCallback(visibilityChangeCB, this); setClassName(thisClassName); firstEvent = TRUE; // set up the device list deviceList = new SbPList; // default devices if (getMouseInput) { mouseDevice = new SoXtMouse(); deviceList->append(mouseDevice); } else mouseDevice = NULL; if (getKeyboardInput) { keybdDevice = new SoXtKeyboard(); deviceList->append(keybdDevice); } else keybdDevice = NULL; // local vars clearFirst = TRUE; clearOverlayFirst = TRUE; autoRedraw = TRUE; selection = overlaySelection = NULL; deviceWidget = NULL; setSize(SbVec2s(400, 400)); // default size setBorder(TRUE); // inventor specific variables appEventHandler = NULL; // the scene manager can be supplied by a subclass., sceneMgr = new SoSceneManager(); sceneMgr->setRenderCallback(renderCB, this); // the overlay scene manager is supplied right here. overlaySceneMgr = new SoSceneManager(); overlaySceneMgr->setRenderCallback(renderOverlayCB, this); // color map variables mapColors = overlayMapColors = NULL; mapColorNum = overlayMapColorNum = 0; // Build the widget tree, and let SoXtComponent know about our base widget. if (buildNow) setBaseWidget(buildWidget(getParentWidget())); } //////////////////////////////////////////////////////////////////////// // // Destructor // SoXtRenderArea::~SoXtRenderArea() // //////////////////////////////////////////////////////////////////////// { // Remove our callback from old selection node if (selection != NULL) { selection->removeChangeCallback(SoXtRenderArea::selectionChangeCB, this); // Unref the old selection node selection->unref(); } unregisterWidget(getGlxMgrWidget()); if (mapColors != NULL) free(mapColors); if (overlayMapColors != NULL) free(overlayMapColors); if (mouseDevice != NULL) delete mouseDevice; if (keybdDevice != NULL) delete keybdDevice; delete sceneMgr; delete overlaySceneMgr; delete deviceList; //??? delete the mouse and keybd if we created them! } //////////////////////////////////////////////////////////////////////// // // Description: // Make the new user supplied scene graph the rendering root. // // use: virtual public // void SoXtRenderArea::setSceneGraph(SoNode *newScene) // //////////////////////////////////////////////////////////////////////// { // Deactivate while we change the scene so that our sensors // get unhooked before the data changes beneath us. sceneMgr->deactivate(); sceneMgr->setSceneGraph(newScene); // draw new scene graphs to the front buffer by default since // the scene will be different (we might has well see something // happening for the first redraw). if (isDrawToFrontBufferEnable()) drawToFrontBuffer = TRUE; // we activate only if we are visible. // after all, if we're not on screen, the visibility change // callback will invoke activate() once we are on screen. if (isVisible() && autoRedraw) { sceneMgr->activate(); sceneMgr->scheduleRedraw(); } } //////////////////////////////////////////////////////////////////////// // // Description: // sets the overlay plane scene graph. // // use: public // void SoXtRenderArea::setOverlaySceneGraph(SoNode *newScene) // //////////////////////////////////////////////////////////////////////// { if (! getOverlayWidget()) return; // Deactivate while we change the scene so that our sensors // get unhooked before the data changes beneath us. overlaySceneMgr->deactivate(); overlaySceneMgr->setSceneGraph(newScene); // we activate only if we are visible. // after all, if we're not on screen, the visibility change // callback will invoke activate() once we are on screen. if (isVisible() && autoRedraw) { overlaySceneMgr->activate(); overlaySceneMgr->scheduleRedraw(); } } //////////////////////////////////////////////////////////////////////// // // Description: // Return the rendering root. // // use: public, virtual // SoNode * SoXtRenderArea::getSceneGraph() // //////////////////////////////////////////////////////////////////////// { return sceneMgr->getSceneGraph(); } //////////////////////////////////////////////////////////////////////// // // Description: // Loads the color map with the given colors. // // use: public // void SoXtRenderArea::setColorMap(int startIndex, int num, const SbColor *colors) // //////////////////////////////////////////////////////////////////////// { // save those colors for future uses (if the widget hasn't been // built yet, or next time it gets built) if (mapColors != NULL) free(mapColors); mapColors = (XColor *) malloc(sizeof(XColor) * num); mapColorNum = num; XColor *xcol = mapColors; for (int i=0; ired = (unsigned short) (colors[i][0] * 65535); xcol->green = (unsigned short) (colors[i][1] * 65535); xcol->blue = (unsigned short) (colors[i][2] * 65535); xcol->flags = DoRed|DoGreen|DoBlue; xcol->pixel = startIndex + i; } // now load those colors into the color map if (colorMap != 0) XStoreColors(getDisplay(), colorMap, mapColors, mapColorNum); } //////////////////////////////////////////////////////////////////////// // // Description: // Loads the overlay color map with the given colors. // // use: public // void SoXtRenderArea::setOverlayColorMap(int startIndex, int num, const SbColor *colors) // //////////////////////////////////////////////////////////////////////// { if (! getOverlayWidget()) return; // save those colors for future uses (if the widget hasn't been // built yet, or next time it gets built) if (overlayMapColors != NULL) free(overlayMapColors); overlayMapColors = (XColor *) malloc(sizeof(XColor) * num); overlayMapColorNum = num; XColor *xcol = overlayMapColors; for (int i=0; ired = (unsigned short) (colors[i][0] * 65535); xcol->green = (unsigned short) (colors[i][1] * 65535); xcol->blue = (unsigned short) (colors[i][2] * 65535); xcol->flags = DoRed|DoGreen|DoBlue; xcol->pixel = startIndex + i; } // now load those colors into the color map if (overlayColorMap != 0) XStoreColors(getDisplay(), overlayColorMap, overlayMapColors, overlayMapColorNum); } //////////////////////////////////////////////////////////////////////// // // Description: // Sets the transparency type // // use: public // void SoXtRenderArea::setTransparencyType(SoGLRenderAction::TransparencyType type) // //////////////////////////////////////////////////////////////////////// { sceneMgr->getGLRenderAction()->setTransparencyType(type); sceneMgr->scheduleRedraw(); } //////////////////////////////////////////////////////////////////////// // // Just call buildWidget on the base class (SoXtGLWidget). // // use: protected // Widget SoXtRenderArea::buildWidget(Widget parent) // //////////////////////////////////////////////////////////////////////// { // Have the parent class build the mgrWidget. // Register the class here, though, since this is where resources // are needed (other GL widgets don't have resources) SoXtGLWidget::buildWidget(parent); registerWidget(getGlxMgrWidget()); // get the resources for this component SoXtResource xr(getGlxMgrWidget()); SbColor c; if (xr.getResource("backgroundColor", "BackgroundColor", c)) setBackgroundColor(c); // get the transparent color index #ifdef GLX_TRANSPARENT_INDEX_VALUE_EXT XVisualInfo *vis = getOverlayVisual(); if (vis != NULL) { int index; glXGetConfig(XtDisplay(parent), vis, GLX_TRANSPARENT_INDEX_VALUE_EXT, &index); overlaySceneMgr->setBackgroundIndex(index); } #endif return getGlxMgrWidget(); } //////////////////////////////////////////////////////////////////////// // // Called by the base class when the frontmost widget changes // (i.e. from single -> double buffer or vice versa). // // use: virtual protected // void SoXtRenderArea::widgetChanged(Widget newWidget) // //////////////////////////////////////////////////////////////////////// { // init the render actions whenever we change windows if (newWidget) sceneMgr->reinitialize(); // // Work around bug #164424 // if we don't use the overlay window, register the devices/handler // on the new normal widget. // if (! getOverlayWidget()) reinstallDevices(newWidget); } //////////////////////////////////////////////////////////////////////// // // Register interest to handle events for the passed device. // If device is already in the list, then make sure it's enabled. // // use: public // void SoXtRenderArea::registerDevice(SoXtDevice *device) // //////////////////////////////////////////////////////////////////////// { // Add the device if it's not already in the list of devices int index = deviceList->find(device); // ??? mott, shouldn't we return if the device is found ? if (index == -1) deviceList->append(device); // tell the device the window size device->setWindowSize(getGlxSize()); // Tell the device to register event interest for our widget Widget w = getOverlayWidget() ? getOverlayWidget() : getNormalWidget(); if ((w != NULL) && (XtWindow(w) != (Window) NULL)) device->enable( w, (XtEventHandler) SoXtGLWidget::eventHandler, (XtPointer) this, XtWindow(w)); } //////////////////////////////////////////////////////////////////////// // // Unregister interest in the passed device. // // use: public // void SoXtRenderArea::unregisterDevice(SoXtDevice *device) // //////////////////////////////////////////////////////////////////////// { // Find the device in our device list int index = deviceList->find(device); if (index == -1) return; // Remove the device from the list of devices deviceList->remove(index); // Tell the device to register event interest for our widget Widget w = getOverlayWidget() ? getOverlayWidget() : getNormalWidget(); if (w) device->disable( w, (XtEventHandler) SoXtGLWidget::eventHandler, (XtPointer) this); } //////////////////////////////////////////////////////////////////////// // // disable devices on the old widget, and enables them on the new widget. // // use: private // void SoXtRenderArea::reinstallDevices(Widget newWidget) // //////////////////////////////////////////////////////////////////////// { for (int i = 0; i < deviceList->getLength(); i++) { SoXtDevice *device = (SoXtDevice *) (*deviceList)[i]; // disable on the old widget... if (deviceWidget) device->disable( deviceWidget, (XtEventHandler) SoXtGLWidget::eventHandler, (XtPointer) this); // enable on the new widget.... if (newWidget) { device->setWindowSize(getGlxSize()); device->enable( newWidget, (XtEventHandler) SoXtGLWidget::eventHandler, (XtPointer) this, XtWindow(newWidget)); } } // ??? add an event handler to receive EnterNotify events to make // ??? sure the render area has the current keyboard focus, otherwise // ??? keyboard events will go to whichever text field has focus (black // ??? outline around widget). This is the prefered behavior since we // ??? don't want to force the keyboardFocus to be POINTER or require // ??? the user to press a mouse button down. // // We also need a EnterNotify and LeaveNotify to correctly update // stuff for SoLocateHighlight (keep track of current window). // if (deviceWidget) XtRemoveEventHandler(deviceWidget, (EnterWindowMask | LeaveWindowMask), FALSE, (XtEventHandler) SoXtRenderArea::windowEventCB, (XtPointer) this); if (newWidget) XtAddEventHandler(newWidget, (EnterWindowMask | LeaveWindowMask), FALSE, (XtEventHandler) SoXtRenderArea::windowEventCB, (XtPointer) this); deviceWidget = newWidget; } //////////////////////////////////////////////////////////////////////// // // Description: // Invoke the app callback and return what the callback returns. // // use: protected // SbBool SoXtRenderArea::invokeAppCB(XAnyEvent *anyevent) // //////////////////////////////////////////////////////////////////////// { // if app wants event, send event to application if (appEventHandler != NULL) return (*appEventHandler)(appEventHandlerData, anyevent); else return FALSE; } //////////////////////////////////////////////////////////////////////// // // Description: // Process the passed X event. // // use: virtual protected // void SoXtRenderArea::processEvent(XAnyEvent *anyevent) // //////////////////////////////////////////////////////////////////////// { // check if app wants the event... if (invokeAppCB(anyevent)) return; // ...else send it to the scene // to do this, translate the X event to an SoEvent // by finding a device to perform the translation const SoEvent *soevent = NULL; for (int i = 0; (soevent == NULL) && (i < deviceList->getLength()); i++) { SoXtDevice *device = (SoXtDevice *) (*deviceList)[i]; soevent = device->translateEvent(anyevent); } // no device found, so return... if (! soevent) return; // now send the event first to the overlay scene graph, elses to // the regular scene graph. SbBool handled = overlaySceneMgr->processEvent(soevent); if (! handled) { sceneMgr->processEvent(soevent); // now check to make sure that we updated the handle event action // with the current window the very first time. This is needed // because the SoState does not exists until the action is // applied, and we only update those during enter/leave notify. if (firstEvent) { SoState *state = sceneMgr->getHandleEventAction()->getState(); if (state) { SoWindowElement::set(state, getNormalWindow(), getNormalContext(), getDisplay(), getGLRenderAction()); firstEvent = FALSE; } } } } //////////////////////////////////////////////////////////////////////// // // Initialize the GLX window for rendering. // glXMakeCurrent() should have been called before invoking this routine. // // use: virtual protected // void SoXtRenderArea::initGraphic() // //////////////////////////////////////////////////////////////////////// { sceneMgr->reinitialize(); sceneMgr->setRGBMode(isRGBMode()); SoGLRenderAction *ra = sceneMgr->getGLRenderAction(); ra->setCacheContext(getDisplayListShareGroup(getNormalContext())); ra->setRenderingIsRemote(!glXIsDirect(getDisplay(), getNormalContext())); // load the color map if (! isRGBMode() && colorMap != 0 && mapColorNum != 0) XStoreColors(getDisplay(), colorMap, mapColors, mapColorNum); } //////////////////////////////////////////////////////////////////////// // // Initialize the GLX window for rendering. // glXMakeCurrent() should have been called before invoking this routine. // // use: virtual protected // void SoXtRenderArea::initOverlayGraphic() // //////////////////////////////////////////////////////////////////////// { overlaySceneMgr->reinitialize(); overlaySceneMgr->setRGBMode(FALSE); SoGLRenderAction *ra = overlaySceneMgr->getGLRenderAction(); ra->setCacheContext(getDisplayListShareGroup(getOverlayContext())); ra->setRenderingIsRemote(!glXIsDirect(getDisplay(), getOverlayContext())); // load the color map if (overlayColorMap != 0 && overlayMapColorNum != 0) XStoreColors(getDisplay(), overlayColorMap, overlayMapColors, overlayMapColorNum); // enable the devices on the overlay window reinstallDevices(getOverlayWidget()); } //////////////////////////////////////////////////////////////////////// // // Called by the base class (SoXtGLWidget) when the widget has changed size. // // use: virtual protected // void SoXtRenderArea::sizeChanged(const SbVec2s &newSize) // //////////////////////////////////////////////////////////////////////// { sceneMgr->setWindowSize(newSize); overlaySceneMgr->setWindowSize(newSize); // tell each device the new window size for (int i = 0; i < deviceList->getLength(); i++) { SoXtDevice *device = (SoXtDevice *) (*deviceList)[i]; device->setWindowSize(newSize); } } //////////////////////////////////////////////////////////////////////// // // Attach the sensor (if necessary). // // use: private // void SoXtRenderArea::activate() // //////////////////////////////////////////////////////////////////////// { // if autoRedraw is off, then don't attach the scene sensor if (! autoRedraw) return; // Activate the scene manager sceneMgr->activate(); overlaySceneMgr->activate(); } //////////////////////////////////////////////////////////////////////// // // Detach the sensor. // // use: private // void SoXtRenderArea::deactivate() // //////////////////////////////////////////////////////////////////////// { // detach sensors sceneMgr->deactivate(); overlaySceneMgr->deactivate(); } //////////////////////////////////////////////////////////////////////// // // Turn auto-redraw on or off. If turning on, then activate the scene // sensor. // // use: public // void SoXtRenderArea::setAutoRedraw(SbBool flag) // //////////////////////////////////////////////////////////////////////// { if (flag == autoRedraw) return; autoRedraw = flag; if (autoRedraw) { if (isVisible()) activate(); } else deactivate(); } //////////////////////////////////////////////////////////////////////// // // Have the scene manager redraw the scene. // // use: virtual protected // void SoXtRenderArea::actualRedraw() // //////////////////////////////////////////////////////////////////////// { sceneMgr->render(clearFirst); } //////////////////////////////////////////////////////////////////////// // // Have the scene manager redraw the overlay scene. // // use: virtual protected // void SoXtRenderArea::actualOverlayRedraw() // //////////////////////////////////////////////////////////////////////// { overlaySceneMgr->render(clearOverlayFirst); } //////////////////////////////////////////////////////////////////////// // // This routine draws the scene graph (called by expose events and the // scene graph sensor) // // use: virtual protected // void SoXtRenderArea::redraw() // //////////////////////////////////////////////////////////////////////// { // return if we are not visible or if we need to wait for an expose // event (case when the sensor triggers but we know that an expose // event will come along and we don't want 2 redraws). if (!isVisible() || waitForExpose) return; // set the window glXMakeCurrent(getDisplay(), getNormalWindow(), getNormalContext()); // see if we need to temporary draw to the front buffer (which // is set when we display a new scene or get an expose event) if (drawToFrontBuffer && isDrawToFrontBufferEnable() && isDoubleBuffer()) { // ??? workaround bug 301010 - it seems that redrawing to the front // ??? of a window that might not be on the screen ( isVisible() might // ??? be incorect in a few cases) will confuse the GFX hardware // ??? of some machine (Xtrem and Indy24). // // ??? Note: this also fixes 298058 (redrawing to the front window // ??? on indigo starter gfx, which happened all the time). // if (isRGBMode()) { SbColor color = getBackgroundColor(); glClearColor(color[0], color[1], color[2], 0); } else glClearIndex(getBackgroundIndex()); glClear(GL_COLOR_BUFFER_BIT); glXSwapBuffers(getDisplay(), getNormalWindow()); // ??? end of BUG workaround glReadBuffer(GL_FRONT); // Needed for acbuf antialiasing glDrawBuffer(GL_FRONT); } // draw that scene! (subclasses may redefine...) actualRedraw(); // swap those buffers! if (isDoubleBuffer()) { if (drawToFrontBuffer && isDrawToFrontBufferEnable()) { // no need to swap here - instead restore the buffer and // clear the flag now that we have drawn to the front buffer glReadBuffer(GL_BACK); // Needed for acbuf antialiasing glDrawBuffer(GL_BACK); glFlush(); } else glXSwapBuffers(getDisplay(), getNormalWindow()); } else glFlush(); // clear this flag now that we have drawn drawToFrontBuffer = FALSE; } //////////////////////////////////////////////////////////////////////// // // Description: // Sets antialiasing on GL rendering action. // // use: public // void SoXtRenderArea::setAntialiasing(SbBool smoothing, int numPasses) // //////////////////////////////////////////////////////////////////////// { SoGLRenderAction *ra = getGLRenderAction(); if (smoothing == ra->isSmoothing() && numPasses == ra->getNumPasses()) return; // The visual needs to change if we are now enabling or disabling // the accumulation buffer SbBool needToChangeVisual = ((numPasses > 1 && ra->getNumPasses() == 1) || (numPasses == 1 && ra->getNumPasses() > 1)); // // now create a visual with the right info - this tries to // preserve as many setting as the original visual, with just // the antialiasing changed. // if (needToChangeVisual) { int n = 0; int attribList[20]; if (isRGBMode()) { 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; } // there is always zbuffer... attribList[n++] = GLX_DEPTH_SIZE; attribList[n++] = 1; if (isDoubleBuffer()) attribList[n++] = GLX_DOUBLEBUFFER; // now add the antialiasing stuff if (numPasses > 1) { attribList[n++] = GLX_ACCUM_RED_SIZE; attribList[n++] = 1; attribList[n++] = GLX_ACCUM_GREEN_SIZE; attribList[n++] = 1; attribList[n++] = GLX_ACCUM_BLUE_SIZE; attribList[n++] = 1; } // check for stencil buffer Widget w = getWidget(); XVisualInfo *normalVis = getNormalVisual(); if (normalVis) { int val; glXGetConfig(XtDisplay(w), normalVis, GLX_STENCIL_SIZE, &val); if (val) { attribList[n++] = GLX_STENCIL_SIZE; attribList[n++] = val; } } attribList[n++] = (int) None; // create the visual XVisualInfo *vis = glXChooseVisual(XtDisplay(w), XScreenNumberOfScreen(XtScreen(w)), attribList); if (! vis) { #ifdef DEBUG SoDebugError::post("SoXtRenderArea::setAntialiasing", "could not create ACCUM visual"); #endif return; } // now set this as the current visual setNormalVisual(vis); // GL widget made a copy - we can free this XFree(vis); } else // only the number of passes changed, so just redraw sceneMgr->scheduleRedraw(); // finally set the stuff on the render action sceneMgr->setAntialiasing(smoothing, numPasses); } //////////////////////////////////////////////////////////////////////// // // This routine draws the scene graph for the overlay bit planes (called // by the expose event and scene graph sensor). // // use: virtual protected // void SoXtRenderArea::redrawOverlay() // //////////////////////////////////////////////////////////////////////// { if (!isVisible() || getOverlayWindow() == (Window) NULL) return; // set the window glXMakeCurrent(getDisplay(), getOverlayWindow(), getOverlayContext()); // draw that scene! (subclasses may redefine...) actualOverlayRedraw(); glFlush(); } //////////////////////////////////////////////////////////////////////// // // Schedule a redraw to happen sometime soon. // // use: public // void SoXtRenderArea::scheduleRedraw() // //////////////////////////////////////////////////////////////////////// { if (isAutoRedraw()) sceneMgr->scheduleRedraw(); else redraw(); } //////////////////////////////////////////////////////////////////////// // // Schedule a redraw to happen sometime soon. // // use: public // void SoXtRenderArea::scheduleOverlayRedraw() // //////////////////////////////////////////////////////////////////////// { if (isAutoRedraw()) overlaySceneMgr->scheduleRedraw(); else redrawOverlay(); } //////////////////////////////////////////////////////////////////////// // // Convenience to set up the redraw mechansim whenever the selection // changes. // // public // void SoXtRenderArea::redrawOnSelectionChange(SoSelection *s) // //////////////////////////////////////////////////////////////////////// { // Ref the new selection node if (s != NULL) s->ref(); // Remove our callback from old selection node if (selection != NULL) { selection->removeChangeCallback(SoXtRenderArea::selectionChangeCB, this); // Unref the old selection node selection->unref(); } selection = s; // Add our callback to this selection node. (We've already ref'd this new sel node) if (selection != NULL) selection->addChangeCallback(SoXtRenderArea::selectionChangeCB, this); } //////////////////////////////////////////////////////////////////////// // // Convenience to set up the redraw mechansim whenever the selection // changes. // // public // void SoXtRenderArea::redrawOverlayOnSelectionChange(SoSelection *s) // //////////////////////////////////////////////////////////////////////// { // Remove our callback from old selection node if (overlaySelection != NULL) overlaySelection->removeChangeCallback(SoXtRenderArea::overlaySelectionChangeCB, this); overlaySelection = s; // Add our callback to this selection node if (overlaySelection != NULL) overlaySelection->addChangeCallback(SoXtRenderArea::overlaySelectionChangeCB, this); } // // redefine those generic virtual functions // const char * SoXtRenderArea::getDefaultWidgetName() const { return thisClassName; } const char * SoXtRenderArea::getDefaultTitle() const { return "Xt RenderArea"; } const char * SoXtRenderArea::getDefaultIconTitle() const { return "Xt RenderArea"; } // //////////////////////////////////////////////////////////////////////// // static callbacks stubs //////////////////////////////////////////////////////////////////////// // #include // // Called whenever an enter/leave window event occurs. This forces the // render area to get/loose keyboard Focus (as opposed to requiring // POINTER focus policy, or requiring the user to press a mouse // button down). // // We also need a EnterNotify and LeaveNotify to correctly update // stuff for SoLocateHighlight (keep track of current window). // void SoXtRenderArea::windowEventCB(Widget w, SoXtRenderArea *p, XAnyEvent *xe, Boolean *) { if (xe->type == EnterNotify) { // get keyboard focus.... if (p->getOverlayWidget()) XmProcessTraversal(p->getOverlayWidget(), XmTRAVERSE_CURRENT); else XmProcessTraversal(p->getNormalWidget(), XmTRAVERSE_CURRENT); // // update the windowElement for the handleEventAction as well // as the GLRenderAction to point to this window. // // Note: don't touch the windowElement if we are in the middle // of rendering (if we process event during render abort). // SoState *state = p->sceneMgr->getHandleEventAction()->getState(); if (state) SoWindowElement::set(state, p->getNormalWindow(), p->getNormalContext(), p->getDisplay(), p->getGLRenderAction()); state = p->sceneMgr->getGLRenderAction()->getState(); if (state && state->getDepth() == 1) SoWindowElement::set(state, p->getNormalWindow(), p->getNormalContext(), p->getDisplay(), p->getGLRenderAction()); } else if (xe->type == LeaveNotify) { // loose keyboard focus... XmProcessTraversal(SoXt::getShellWidget(w), XmTRAVERSE_CURRENT); // // clear the windowElement from the actions now that we are // leaving the window. // // Note: don't touch the windowElement if we are in the middle // of rendering (if we process event during render abort). // // but first clear any currently highlighted object SoGLRenderAction *glAct = p->sceneMgr->getGLRenderAction(); if (glAct) SoLocateHighlight::turnOffCurrentHighlight(glAct); SoState *state = p->sceneMgr->getHandleEventAction()->getState(); if (state) SoWindowElement::set(state, (Window) NULL, NULL, NULL, NULL); state = p->sceneMgr->getGLRenderAction()->getState(); if (state && state->getDepth() == 1) SoWindowElement::set(state, (Window) NULL, NULL, NULL, NULL); } } // // called whenever the component becomes visible or not // void SoXtRenderArea::visibilityChangeCB(void *pt, SbBool visible) { SoXtRenderArea *p = (SoXtRenderArea *)pt; if (visible) p->activate(); else { // we are becoming hidden - so wait for an expose event // (which we now will come later) before enabling a redraw to // prevent too many redraws (scene graph changes + expose) p->waitForExpose = TRUE; p->deactivate(); } } void SoXtRenderArea::selectionChangeCB(void *p, SoSelection *) { ((SoXtRenderArea *)p)->scheduleRedraw(); } void SoXtRenderArea::overlaySelectionChangeCB(void *p, SoSelection *) { ((SoXtRenderArea *)p)->scheduleOverlayRedraw(); } void SoXtRenderArea::renderCB(void *p, SoSceneManager *) { ((SoXtRenderArea *)p)->redraw(); } void SoXtRenderArea::renderOverlayCB(void *p, SoSceneManager *) { ((SoXtRenderArea *)p)->redrawOverlay(); }