File: [Development] / inventor / libSoXt / src / SoXt.c++ (download)
Revision 1.2, Wed Aug 23 05:21:38 2000 UTC (17 years, 2 months ago) by jlim
Branch: MAIN
Changes since 1.1: +3 -3
lines
Fix for Bug 769748: Purify FMM when running IvClock demo.
|
/*
*
* 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:
| SoXt
| SoXtEventHandler
|
| Author(s): David Mott, Nick Thompson, Paul Isaacs, Alain Dumesny
|
______________ S I L I C O N G R A P H I C S I N C . ____________
_______________________________________________________________________
*/
#include <Inventor/errors/SoDebugError.h>
#include <Inventor/SoDB.h>
#include <Inventor/SoInteraction.h>
#include <Inventor/nodekits/SoNodeKit.h>
#include <Inventor/sensors/SoSensorManager.h>
#include <Inventor/Xt/SoXt.h>
#include <Xm/MessageB.h>
#include <SoDebug.h>
#include <X11/Intrinsic.h>
#include <X11/Xresource.h>
#include <X11/StringDefs.h>
// This SG_ routine is from /usr/src/X11/motif/overlay_demos.
// Someday, it may be a standard function in a lib, but for
// now it is just sample code. We include it here for convenience
// to our users.
extern "C" {
iv_SG_getPopupArgs(Display *, int, ArgList, int *);
}
#include <SoDebug.h>
static void overlayMenuMappedCB(Widget w, Widget shell, XtPointer);
static void overlayMenuUnmappedCB(Widget w, Widget shell, XtPointer);
// this class ties Inventor sensors into Xt events
class SoXtEventHandler {
public:
SoXtEventHandler(XtAppContext context);
private:
XtAppContext appContext;
SbBool timerOn;
XtIntervalId xtTimer;
SbTime currentDeadline;
SbBool workProcOn;
XtWorkProcId xtWorkProc;
// Callback used by the timer
static void xtTimerCallback(XtPointer closure, XtIntervalId *id);
// Callback used by the workproc
static Boolean xtWorkProcCallback(XtPointer closure);
// Callback for changes to the sensor manager
static void sensorManagerChangedCallback(void *data);
void setUpCallbacks();
};
class SoExtensionEventHandler {
public:
SoExtensionEventHandler(
Widget widget,
int eventType,
XtEventHandler proc,
XtPointer data);
Widget getWidget() { return widget; }
int getEventType() { return eventType; }
XtEventHandler getEventHandler() { return proc; }
XtPointer getClientData() { return data; }
private:
Widget widget;
int eventType;
XtEventHandler proc;
XtPointer data;
};
// static members
Widget SoXt::mainWidget = 0;
SoXtEventHandler * SoXt::eventHandler = NULL;
SbPList * SoXt::handlerList = NULL;
////////////////////////////////////////////////////////////////////////
//
// Description:
// This initializes the database, interaction, and Xt.
// It creates a returns a top level shell widget.
//
// static public
//
Widget
SoXt::init(
const char *appName,
const char *className)
//
////////////////////////////////////////////////////////////////////////
{
// see if we are already initialized!
if (mainWidget != NULL)
return mainWidget;
// init Xt, and store the widget it returns.
XtAppContext appContext;
char *argv[1];
int argc = 1;
argv[0] = (char *) appName;
mainWidget = XtAppInitialize(
&appContext, // context will be returned
className, // application class
NULL, 0, // options
(int *) &argc, argv, // command line args (appName!)
NULL, // fallback_resources
NULL, 0); // args, num_args
// init Inventor
SoDB::init();
SoNodeKit::init();
SoInteraction::init();
// bind Inventor with Xt
eventHandler = new SoXtEventHandler(XtWidgetToApplicationContext(mainWidget));
return mainWidget;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// This initializes the database and interaction. Xt was initialized
// by the caller.
//
// static public
//
void
SoXt::init(Widget topLevelWidget)
//
////////////////////////////////////////////////////////////////////////
{
// see if we are already initialized!
if (mainWidget != NULL)
return;
// see if the passed widget is ok
if (topLevelWidget == NULL)
return;
// save the widget
mainWidget = topLevelWidget;
// init Inventor
SoDB::init();
SoNodeKit::init();
SoInteraction::init();
// bind Inventor with Xt
eventHandler = new SoXtEventHandler(XtWidgetToApplicationContext(mainWidget));
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// This displays the passed widget.
//
// static public
//
void
SoXt::show(Widget w)
//
////////////////////////////////////////////////////////////////////////
{
if (w == NULL)
return;
if (XtIsShell(w)) {
// raise and de-iconify the window if it already exists
if (XtWindow(w) != 0)
XMapRaised(XtDisplay(w), XtWindow(w));
else {
XtRealizeWidget(w);
XMapWindow(XtDisplay(w), XtWindow(w));
}
}
else
XtManageChild(w);
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// This hides the passed widget.
//
// static public
//
void
SoXt::hide(Widget w)
//
////////////////////////////////////////////////////////////////////////
{
if (w == NULL)
return;
// ??? temporary disable the idle queue timer to prevent a redraw timer
// ??? from happening before we get chance to process all unmap events
// ??? that will be generated from this hide(). SoXtComponents will
// ??? depend of those unmap events to know that they are not visible.
// ??? .....see comment below about XSync()......
SbTime savedTime = SoDB::getDelaySensorTimeout();
if (savedTime != SbTime::zero())
SoDB::setDelaySensorTimeout(0.0);
if (XtIsShell(w)) {
if (XtWindow(w))
XUnmapWindow(XtDisplay(w), XtWindow(w));
}
else
XtUnmanageChild(w);
// call XSync() to force the unmap events to be received by the X server,
// which are needed to prevent SoXtComponents from redrawing into a
// window that is unmaped. Redrawing to an unmapped window seems to
// screw up some hardware gfx the NEXT time you redraw to the
// front buffer. (see bug 290854)
XSync(XtDisplay(w), FALSE);
// ??? restore the timer. This actually will give us about 1/10 second to
// ??? process all unmap events...idealy we could use an XSendEvent() to
// ??? restore the timer with our onw event.
if (savedTime != SbTime::zero())
SoDB::setDelaySensorTimeout(savedTime);
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// This adds the passed proc as an event handler for an X extension
// event.
//
// static public
//
void
SoXt::addExtensionEventHandler(
Widget w,
int extensionEventType,
XtEventHandler proc,
XtPointer clientData)
//
////////////////////////////////////////////////////////////////////////
{
if (handlerList == NULL)
handlerList = new SbPList;
// add the passed proc as an event handler for extension events on w
SoExtensionEventHandler *data = new SoExtensionEventHandler
(w, extensionEventType, proc, clientData);
handlerList->append(data);
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// This removes the passed proc as an event handler for and X extension
// event.
//
// static public
//
void
SoXt::removeExtensionEventHandler(
Widget w,
int extensionEventType,
XtEventHandler proc,
XtPointer clientData)
//
////////////////////////////////////////////////////////////////////////
{
// loop through each item in handlerList,
// and see if w,eventType,proc, and data match.
SbBool found = FALSE;
for (int i = 0; !found && (i < handlerList->getLength()); i++) {
SoExtensionEventHandler *handler =
(SoExtensionEventHandler *) (*handlerList)[i];
if ((handler->getWidget() == w) &&
(handler->getEventType() == extensionEventType) &&
(handler->getEventHandler() == proc) &&
(handler->getClientData() == clientData)) {
found = TRUE;
handlerList->remove(i);
}
}
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// This locates the widget which will handle the event.
// Input: event
// Output: w, proc, clientData
//
// static protected
//
void
SoXt::getExtensionEventHandler(
XEvent *event,
Widget &w,
XtEventHandler &proc,
XtPointer &clientData)
//
////////////////////////////////////////////////////////////////////////
{
// extension event. look up in our list of event handlers
// for a match
proc = NULL;
for (int i = 0; (proc == NULL) && (i < handlerList->getLength()); i++) {
SoExtensionEventHandler *handler =
(SoExtensionEventHandler *) (*handlerList)[i];
w = XtWindowToWidget(event->xany.display,
event->xany.window);
if (handler->getWidget() == w) {
if (handler->getEventType() == event->type) {
// we found a match!
proc = handler->getEventHandler();
clientData = handler->getClientData();
}
}
}
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// This dispatches events.
//
// static public
//
Boolean
SoXt::dispatchEvent(XEvent *event)
//
////////////////////////////////////////////////////////////////////////
{
Boolean success = True;
if(event->type >= LASTEvent) {
XtEventHandler proc;
XtPointer clientData;
Widget w;
Boolean dummy;
// Get the event handling function which was
// registered with Inventor for handling this
// event type in this widget
SoXt::getExtensionEventHandler(event, w, proc, clientData);
// Call the event handler!
if (proc == NULL)
success = False;
else
(*proc) (w, clientData, event, &dummy);
}
// else it is not an extension event - let Xt dispatch it
else success = XtDispatchEvent(event);
return success;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// This retrieves and dispatches events (it loops forever!)
//
// static public
//
void
SoXt::mainLoop()
//
////////////////////////////////////////////////////////////////////////
{
if (mainWidget == NULL) {
#ifdef DEBUG
SoDebugError::post("SoXt::mainLoop",
"exiting -- SoXt::init never called");
#endif
return;
}
// We cannot call XtAppMainLoop, because we need to handle
// extension devices, like the spaceball. (Xt will ignore them).
XtAppContext context = getAppContext();
XEvent event;
for (;;) {
SoXt::nextEvent(context, &event);
SoXt::dispatchEvent(&event);
}
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// This returns the application context for the mainWidget.
//
// static public
//
XtAppContext
SoXt::getAppContext()
//
////////////////////////////////////////////////////////////////////////
{
return mainWidget == NULL ? NULL : XtWidgetToApplicationContext(mainWidget);
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// This returns the display for the mainWidget.
//
// static public
//
Display *
SoXt::getDisplay()
//
////////////////////////////////////////////////////////////////////////
{
return mainWidget == NULL ? NULL : XtDisplay(mainWidget);
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// This returns the display for the mainWidget.
//
// static public
//
Widget
SoXt::getTopLevelWidget()
//
////////////////////////////////////////////////////////////////////////
{
return mainWidget;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Convert the char* to an XmString.
//
// static public
//
XmString
SoXt::encodeString(char *s)
//
////////////////////////////////////////////////////////////////////////
{
XmString xs = NULL;
if (s != NULL)
xs = XmStringCreate(s, XmSTRING_DEFAULT_CHARSET);
return xs;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Convert the XmString to a char*.
//
// static public
//
char *
SoXt::decodeString(XmString xs)
//
////////////////////////////////////////////////////////////////////////
{
XmStringContext ctx;
char *text = NULL;
XmStringCharSet charset;
XmStringDirection dirRtoL;
Boolean separator;
Boolean initOK = TRUE;
Boolean getOK = TRUE;
initOK = XmStringInitContext(&ctx, xs);
if (initOK)
getOK = XmStringGetNextSegment(ctx, &text,
&charset, &dirRtoL, &separator);
#ifdef DEBUG
if (!initOK)
SoDebugError::post("SoXt::decodeString",
"XmStringInitContext failed.");
if (!getOK)
SoDebugError::post("SoXt::decodeString",
"XmStringGetNextSegment failed.");
#endif
return text;
}
//----------------------------------------------------------------------
//
// SoXtEventHandler - this class ties in sensors to Xt events
//
//----------------------------------------------------------------------
SoXtEventHandler::SoXtEventHandler(XtAppContext context)
{
appContext = context;
timerOn = FALSE;
workProcOn = FALSE;
SoDB::getSensorManager()->setChangedCallback
(SoXtEventHandler::sensorManagerChangedCallback,
this);
// Call this once because things might already be in the timer queue.
// If we don't call this and no new things happen, then the callbacks
// will never be set up.
setUpCallbacks();
}
void
SoXtEventHandler::setUpCallbacks()
{
SbTime nextEvent;
// If we have a timer at some point, schedule that
if (SoDB::getSensorManager()->isTimerSensorPending(nextEvent)) {
// Only change the timer if its deadline is different from the
// current one.
if (!timerOn || nextEvent != currentDeadline) {
long msec; // System long
if (timerOn) { // get rid of existing timer if present
XtRemoveTimeOut(xtTimer);
timerOn = FALSE;
}
currentDeadline = nextEvent;
msec = (nextEvent - SbTime::getTimeOfDay()).getMsecValue();
xtTimer = XtAppAddTimeOut(appContext, msec > 0 ? msec : 0,
(XtTimerCallbackProc)
SoXtEventHandler::xtTimerCallback,
(XtPointer) this);
timerOn = TRUE;
#ifdef DEBUG
if (SoDebug::GetEnv("IV_DEBUG_SENSORS")) {
SoDebug::RTPrintf("XtAppAddTimeOut %d msec\n", msec);
}
#endif
}
}
else if (timerOn) { // get rid of existing timer
XtRemoveTimeOut(xtTimer);
timerOn = FALSE;
#ifdef DEBUG
if (SoDebug::GetEnv("IV_DEBUG_SENSORS")) {
SoDebug::RTPrintf("XtRemoveTimeOut\n");
}
#endif
}
// If we have an idle task, schedule a workproc for it
if (SoDB::getSensorManager()->isDelaySensorPending()) {
// only schedule it if one is not already active
if (!workProcOn) {
xtWorkProc =
XtAppAddWorkProc(appContext,
(XtWorkProc)
SoXtEventHandler::xtWorkProcCallback,
(XtPointer) this);
workProcOn = TRUE;
#ifdef DEBUG
if (SoDebug::GetEnv("IV_DEBUG_SENSORS")) {
SoDebug::RTPrintf("XtAppAddWorkProc\n");
}
#endif
}
}
else if (workProcOn) { // remove obsolete workproc
XtRemoveWorkProc(xtWorkProc);
workProcOn = FALSE;
#ifdef DEBUG
if (SoDebug::GetEnv("IV_DEBUG_SENSORS")) {
SoDebug::RTPrintf("XtRemoveWorkProc\n");
}
#endif
}
}
void
SoXtEventHandler::xtTimerCallback(XtPointer closure, XtIntervalId *)
{
SoXtEventHandler *eh = (SoXtEventHandler *) closure;
// process the timer queue
SoDB::getSensorManager()->processTimerQueue();
// set up for the next time around
// hide the fact that this timer exists so that setUpEvents
// won't try to delete it (Xt will do that automatically)
eh->timerOn = FALSE;
eh->setUpCallbacks();
}
Boolean
SoXtEventHandler::xtWorkProcCallback(XtPointer closure)
{
SoXtEventHandler *eh = (SoXtEventHandler *) closure;
// process the idle queue
SoDB::getSensorManager()->processDelayQueue(TRUE);
// set up for the next time around
// hide the fact that this workproc exists so that setUpEvents
// won't try to delete it (Xt will do that automatically)
eh->workProcOn = FALSE;
eh->setUpCallbacks();
// Always return TRUE, meaning delete the workproc now. The
// workproc will be installed again if it is necessary. This
// should be pretty cheap, as Xt keeps a pool of these.
return TRUE;
}
// Callback for changes to the sensor manager
void
SoXtEventHandler::sensorManagerChangedCallback(void *data)
{
SoXtEventHandler *eh = (SoXtEventHandler *) data;
// update the Xt timeout and workproc if necessary
eh->setUpCallbacks();
}
SoExtensionEventHandler::SoExtensionEventHandler(
Widget w,
int et,
XtEventHandler p,
XtPointer d)
{
widget = w;
eventType = et;
proc = p;
data = d;
}
////////////////////////////////////////////////////////////////////////
//
// Resize the given widget. It calls XtSetArg/Values on the widget.
//
// Use: static public
void
SoXt::setWidgetSize(Widget w, const SbVec2s &size)
//
////////////////////////////////////////////////////////////////////////
{
if (w == NULL)
return;
Arg args[2];
XtSetArg(args[0], XtNwidth, size[0]);
XtSetArg(args[1], XtNheight, size[1]);
XtSetValues(w, args, 2);
}
////////////////////////////////////////////////////////////////////////
//
// Returns the given widget size.
//
// Use: static public
SbVec2s
SoXt::getWidgetSize(Widget w)
//
////////////////////////////////////////////////////////////////////////
{
if (w == NULL)
return SbVec2s(0, 0);
Arg args[2];
short _w, _h; // HAS to be shorts for XtGetValues to work !!
XtSetArg(args[0], XtNheight, &_h);
XtSetArg(args[1], XtNwidth, &_w);
XtGetValues(w, args, 2);
return SbVec2s(_w, _h);
}
////////////////////////////////////////////////////////////////////////
//
// Returns the shell widget which contains this widget
//
// Use: static public
Widget
SoXt::getShellWidget(Widget w)
//
////////////////////////////////////////////////////////////////////////
{
for (; w != NULL; w = XtParent(w))
if (XtIsShell(w))
return w;
return NULL;
}
static void destroyDialogCB(Widget dialog, void *, void *)
{ XtDestroyWidget(dialog); }
////////////////////////////////////////////////////////////////////////
//
// creates a simple error dialog box with the given error
//
// Use: static public
void
SoXt::createSimpleErrorDialog(Widget widget,
char *dialogTitle, char *str1, char *str2)
//
////////////////////////////////////////////////////////////////////////
{
// ??? Make the motif dialog on the shell of the 'widget' variable
// ??? instead of the 'widget' itself otherwise the color editor
// ??? has problem building once the dialog has been opened.
// ??? I can't figure that one out. Weird... (alain)
Widget shell = SoXt::getShellWidget(widget);
if (shell == NULL)
return;
Arg args[5];
XmString xmstr = XmStringCreateSimple(str1);
if (str2 != NULL) {
xmstr = XmStringConcat(xmstr, XmStringSeparatorCreate());
xmstr = XmStringConcat(xmstr, XmStringSeparatorCreate());
xmstr = XmStringConcat(xmstr, XmStringCreateSimple(str2));
}
int n = 0;
XtSetArg(args[n], XmNautoUnmanage, FALSE); n++;
XtSetArg(args[n], XtNtitle, dialogTitle); n++;
XtSetArg(args[n], XmNmessageString, xmstr); n++;
XtSetArg(args[n], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); n++;
Widget dialog = XmCreateErrorDialog(shell, "Error Dialog", args, n);
XmStringFree(xmstr);
XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
// register callback to destroy (and not just unmap) the dialog
XtAddCallback(dialog, XmNokCallback,
(XtCallbackProc) destroyDialogCB, (XtPointer)NULL);
XtManageChild(dialog);
}
////////////////////////////////////////////////////////////////////////
//
// Convenience routine for creating menus in the popup planes.
//
// Use: static public
void
SoXt::getPopupArgs(
Display *d,
int scr,
ArgList args,
int *n)
//
////////////////////////////////////////////////////////////////////////
{
iv_SG_getPopupArgs(d, scr, args, n);
}
////////////////////////////////////////////////////////////////////////
//
// register map/unmap callbacks to load/unload the given color maps
// when the pulldown menu (or popup menu) gets mapped.
//
// Use: static public
void
SoXt::registerColormapLoad(Widget w, Widget shell)
//
////////////////////////////////////////////////////////////////////////
{
if (! w || ! shell || ! XtIsShell(shell))
return;
XtAddCallback(w, XmNmapCallback, (XtCallbackProc) overlayMenuMappedCB, shell);
XtAddCallback(w, XmNunmapCallback, (XtCallbackProc) overlayMenuUnmappedCB, shell);
}
//
// Called when an overlay menu (pulldown or popup) is about to be
// mapped - this will load the correct color map on the window.
//
static void
overlayMenuMappedCB(Widget w, Widget shell, XtPointer)
{
//printf("MAP overlayMenuMappedCB called\n");
SoXt::addColormapToShell(w, shell);
}
//
// Called when an overlay menu (pulldown or popup) is no longer
// mapped - this will unload the color map to make sure that the OGL
// overlay (really popup planes on 8 bit machine) colormap gets used.
//
static void
overlayMenuUnmappedCB(Widget w, Widget shell, XtPointer)
{
//printf("UNMAP overlayMenuUnmappedCB called\n");
SoXt::removeColormapFromShell(w, shell);
}
////////////////////////////////////////////////////////////////////////
//
// Convenience routine to load the given colormap
//
// Use: static public
void
SoXt::addColormapToShell(Widget w, Widget shell)
//
////////////////////////////////////////////////////////////////////////
{
if (! w || ! shell || ! XtIsShell(shell))
return;
// load the color map RIGH AWAY to reduce pulldown menu flickers
Colormap map;
XtVaGetValues(w, XmNcolormap, &map, NULL);
XInstallColormap(XtDisplay(w), map);
// check to see if there is already a property
Window *windowsReturn;
int countReturn;
Status status = XGetWMColormapWindows(XtDisplay(shell),
XtWindow(shell), &windowsReturn, &countReturn);
// if no property, just create one
if (!status)
{
Window windows[2];
windows[0] = XtWindow(w);
windows[1] = XtWindow(shell);
XSetWMColormapWindows(XtDisplay(shell), XtWindow(shell),
windows, 2);
}
// else there was a property, add myself to the beginning
else {
Window *windows = (Window *)XtMalloc((sizeof(Window))*
(countReturn+1));
windows[0] = XtWindow(w);
for (int i=0; i<countReturn; i++)
windows[i+1] = windowsReturn[i];
XSetWMColormapWindows(XtDisplay(shell), XtWindow(shell),
windows, countReturn+1);
XtFree((char *)windows);
XFree((char *)windowsReturn);
}
}
////////////////////////////////////////////////////////////////////////
//
// Convenience routine to remove the given colormap
//
void
SoXt::removeColormapFromShell(Widget w, Widget shell)
//
////////////////////////////////////////////////////////////////////////
{
if (! w || ! shell || ! XtIsShell(shell))
return;
// check to see if there is a property
Window *windowsReturn;
int countReturn;
Status status = XGetWMColormapWindows(XtDisplay(shell),
XtWindow(shell), &windowsReturn, &countReturn);
// if no property, just return. If there was a property, continue
if (status)
{
// search for a match
for (int i=0; i<countReturn; i++)
{
if (windowsReturn[i] == XtWindow(w))
{
// we found a match, now copu the rest down
for (i++; i<countReturn; i++)
windowsReturn[i-1] = windowsReturn[i];
XSetWMColormapWindows(XtDisplay(w), XtWindow(shell),
windowsReturn, countReturn-1);
break; // from outer for
}
}
XFree((char *)windowsReturn);
}
}