1 /***********************************************************************/
2 /* Open Visualization Data Explorer                                    */
3 /* (C) Copyright IBM Corp. 1989,1999                                   */
4 /* ALL RIGHTS RESERVED                                                 */
5 /* This code licensed under the                                        */
6 /*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
7 /***********************************************************************/
8 
9 #include <dxconfig.h>
10 #include "../base/defines.h"
11 
12 
13 
14 #include <Xm/CascadeB.h>
15 #include <Xm/CascadeBG.h>
16 
17 #include "XmUtility.h"
18 #include "DXStrings.h"
19 #include "WorkSpaceComponent.h"
20 #include "DXApplication.h"
21 #include "../widgets/WorkspaceW.h"
22 #include <Xm/Form.h>
23 #include <Xm/Label.h>
24 #include "List.h"
25 #include "ListIterator.h"
26 #include "DynamicResource.h"
27 #include "Network.h" // for setFileDirty
28 
29 boolean WorkSpaceComponent::WorkSpaceComponentClassInitialized = FALSE;
30 
31 #if KEEP_USING_TRANSLATIONS
32 static XtTranslations wwTranslations = 0;
33 //
34 // This translation table makes descendants of a Workspace widget participate
35 // in selecting, moving, and resizing operations.  This is an alternative to
36 // the ::PassEvents() method which used to do some Xlib stuff.  PassEvents()
37 // is now replaced with a call to install this translation table on a widget.
38 // The call is now ::passEvents -- it's not static and it uses the "this" pointer.
39 //
40 static String wwTable = "\
41  <Btn1Down>:    select_w()\n\
42  <Btn1Motion>:  move_w()\n\
43  <Btn1Up>(2+):  select_w() release_w() select_w() release_w()\n\
44  <Btn1Up>:      release_w()\n\
45 ";
46 #else
47 //
48 // Stop using translations and use event handlers instead because on some widgets
49 // the <Btn1Motion> translations doesn't do anything until the mouse leaves the
50 // the window which is pretty bizarre behavior, but at least the lower level
51 // mechanism works properly.
52 //
53 #endif
54 
55 long WorkSpaceComponent::NextInstanceNumber = 1;
56 
57 String WorkSpaceComponent::DefaultResources[] =
58 {
59   NUL(char*)
60 };
61 
62 
WorkSpaceComponent(const char * name,boolean developerStyle)63 WorkSpaceComponent::WorkSpaceComponent(const char *name, boolean developerStyle) :
64 	UIComponent(name)
65 {
66     this->developerStyle = developerStyle;
67     this->selected = FALSE;
68     this->customPart = 0;
69     this->visualsInited = FALSE;
70     this->userAssignedWidth = this->userAssignedHeight = 0;
71     this->currentLayout = WorkSpaceComponent::NotSet;
72     this->setResourceList = NUL(List*);
73     this->instance = WorkSpaceComponent::NextInstanceNumber++;
74 
75     if (NOT WorkSpaceComponent::WorkSpaceComponentClassInitialized)
76     {
77         WorkSpaceComponent::WorkSpaceComponentClassInitialized = TRUE;
78 #if KEEP_USING_TRANSLATIONS
79 	wwTranslations = XtParseTranslationTable (wwTable);
80 #endif
81     }
82 }
83 
~WorkSpaceComponent()84 WorkSpaceComponent::~WorkSpaceComponent()
85 {
86     if (this->setResourceList) {
87 	ListIterator it(*this->setResourceList);
88 	DynamicResource *dynres;
89 	while ( (dynres = (DynamicResource *)it.getNext()) ) {
90 	    delete dynres;
91 	}
92 	this->setResourceList->clear();
93 	delete this->setResourceList;
94     }
95 }
96 
97 
98 //
99 // Pass button and motion events through to the parent of w.
100 // The boolean arg is here only because the subclass version of
101 // passEvents needs to have one.
102 //
passEvents(Widget w,boolean)103 void WorkSpaceComponent::passEvents(Widget w, boolean )
104 {
105     ASSERT(WorkSpaceComponent::WorkSpaceComponentClassInitialized);
106 #if KEEP_USING_TRANSLATIONS
107     ASSERT(wwTranslations);
108     XtOverrideTranslations (w, wwTranslations);
109 #else
110     XtAddEventHandler (w, Button1MotionMask, False,
111 	(XtEventHandler)Component_motionEH, (XtPointer)NULL);
112     XtAddEventHandler (w, ButtonPressMask, False,
113 	(XtEventHandler)Component_buttonPressEH, (XtPointer)NULL);
114     XtAddEventHandler (w, ButtonReleaseMask, False,
115 	(XtEventHandler)Component_buttonReleaseEH, (XtPointer)NULL);
116 #endif
117 }
118 
119 
120 extern "C" void
Component_SelectWorkSpaceComponentCB(Widget,XtPointer clientdata,XtPointer callData)121 Component_SelectWorkSpaceComponentCB(Widget , XtPointer clientdata, XtPointer callData)
122 {
123     XmWorkspaceChildCallbackStruct* cb =
124 				(XmWorkspaceChildCallbackStruct*)callData;
125     WorkSpaceComponent	*d = (WorkSpaceComponent*) clientdata;
126     ASSERT(d);
127     d->setSelected(cb->status);
128 }
129 
130 
131 
132 //
133 // Indicate that the interactor is selected.
134 //
setSelected(boolean state)135 void WorkSpaceComponent::setSelected(boolean state)
136 {
137 Widget root = this->getRootWidget();
138 
139     this->selected = state;
140     if (root) {
141 	Boolean oldState;
142 	XtVaGetValues(root, XmNselected, &oldState, NULL);
143 	if (oldState != state) {
144 	    XtVaSetValues(root, XmNselected, (Boolean)state, NULL);
145 	}
146     }
147 }
148 
149 //
150 // Filter the given label string so that among other things, "\n"
151 // becomes "<newline>".  The returned string must be freed by the
152 // caller.
153 //
FilterLabelString(const char * label)154 char *WorkSpaceComponent::FilterLabelString(const char *label)
155 {
156     char *filtered_string = DeEscapeString(label);
157     return filtered_string;
158 }
159 
160 //
161 // Make the interactor "blend into" its environment by turning of
162 // shadowThickness and setting colors to match those of the parent.
163 //
setAppearance(boolean developerStyle)164 void WorkSpaceComponent::setAppearance(boolean developerStyle)
165 {
166 static struct {
167    Pixel fg,bg,ts,bs,arm;
168 } cadet;
169 
170 Pixel fg, bg, ts, bs, arm, white;
171 static short init = 0;
172 Screen *screen;
173 Colormap cmap;
174 Arg args[20];
175 Widget root;
176 
177     if ((this->visualsInited) && (this->developerStyle == developerStyle)) return ;
178     this->visualsInited = TRUE;
179     this->developerStyle = developerStyle;
180     root = this->getRootWidget();
181     if (!root) return ;
182 
183     Display *d = XtDisplay(root);
184     white = WhitePixelOfScreen (DefaultScreenOfDisplay(d));
185 
186     if (developerStyle) {
187 	if (!init) {
188 	   init = 1;
189 	   XtVaGetValues (root, XmNcolormap, &cmap, XmNscreen, &screen, NULL);
190 
191 	   cadet.bg = bg = theDXApplication->getStandInBackground();
192 	   XmGetColors (screen,cmap,bg,&cadet.fg, &cadet.ts, &cadet.bs, &cadet.arm);
193 	   cadet.fg = WhitePixelOfScreen (DefaultScreenOfDisplay(d));
194 	}
195 	bg = cadet.bg; fg = cadet.fg;
196 	ts = cadet.ts; bs = cadet.bs;
197 	arm = cadet.arm;
198     } else {
199 	XtVaGetValues (XtParent(root), XmNbackground, &bg,
200 	     XmNcolormap, &cmap, XmNscreen, &screen, NULL);
201 	XmGetColors (screen, cmap, bg, &fg, &ts, &bs, &arm);
202     }
203 
204 
205     //
206     // Perform a test of DynamicResource by using it set fg,bg,ts, and bs.
207     //
208 //#define TESTING_DYNAMIC_RESOURCE_CLASS 1
209 #if TESTING_DYNAMIC_RESOURCE_CLASS
210     if (!this->setResourceList) {
211 	this->setResourceList = new List;
212 	DynamicResource *drbg = new DynamicResource (XmNbackground, root);
213 	DynamicResource *drfg = new DynamicResource (XmNforeground, root);
214 	DynamicResource *drts = new DynamicResource (XmNtopShadowColor, root);
215 	DynamicResource *drbs = new DynamicResource (XmNbottomShadowColor, root);
216 	DynamicResource *drsc = new DynamicResource (XmNselectColor, root);
217 	DynamicResource *drac = new DynamicResource (XmNarmColor, root);
218 	DynamicResource *drtc = new DynamicResource (XmNtroughColor, root);
219 
220 	this->setResourceList->appendElement ((void *)drbg);
221 	this->setResourceList->appendElement ((void *)drfg);
222 	this->setResourceList->appendElement ((void *)drts);
223 	this->setResourceList->appendElement ((void *)drbs);
224 	this->setResourceList->appendElement ((void *)drsc);
225 	this->setResourceList->appendElement ((void *)drac);
226 	this->setResourceList->appendElement ((void *)drtc);
227 
228 	drbg->setDataDirectly ((void*)bg);
229 	drfg->setDataDirectly ((void*)fg);
230 	drts->setDataDirectly ((void*)ts);
231 	drbs->setDataDirectly ((void*)bs);
232 	drsc->setDataDirectly ((void*)white);
233 	drac->setDataDirectly ((void*)arm);
234 	drtc->setDataDirectly ((void*)arm);
235 
236 	drbg->addWidgetsToNameList (root);
237 	drfg->addWidgetsToNameList (root);
238 	drts->addWidgetsToNameList (root);
239 	drbs->addWidgetsToNameList (root);
240 	drsc->addWidgetsToNameList (root);
241 	drac->addWidgetsToNameList (root);
242 	drtc->addWidgetsToNameList (root);
243     } else {
244 	ListIterator it(*this->setResourceList);
245 	DynamicResource *dr;
246 	while (dr = (DynamicResource*)it.getNext()) {
247 	    const char *cp = dr->getResourceName();
248 	    if (!strcmp(cp, XmNbackground))  dr->setDataDirectly ((void*)bg);
249 	    else if (!strcmp(cp, XmNforeground))  dr->setDataDirectly ((void*)fg);
250 	    else if (!strcmp(cp, XmNtopShadowColor))  dr->setDataDirectly ((void*)ts);
251 	    else if (!strcmp(cp, XmNbottomShadowColor))  dr->setDataDirectly ((void*)bs);
252 	}
253     }
254 
255 #else
256     // Set bg == ts == bs for root widget instead of setting shadowThickness.
257     int n = 0;
258     XtSetArg (args[n], XmNbackground, bg); n++;
259     if (developerStyle) {
260 	XtSetArg (args[n], XmNtopShadowColor, ts); n++;
261 	XtSetArg (args[n], XmNbottomShadowColor, bs); n++;
262     } else {
263 	XtSetArg (args[n], XmNtopShadowColor, bg); n++;
264 	XtSetArg (args[n], XmNbottomShadowColor, bg); n++;
265     }
266     XtSetArg (args[n], XmNselectColor, white); n++;
267     XtSetArg (args[n], XmNarmColor, arm); n++;
268     XtSetArg (args[n], XmNtroughColor, arm); n++;
269     XtSetArg (args[n], XmNforeground, fg); n++;
270     XtSetArg (args[n], XmNselectable, (developerStyle?True:False) ); n++;
271     XtSetValues (root, args, n);
272 
273     n = 0;
274     XtSetArg (args[n], XmNbackground, bg); n++;
275     XtSetArg (args[n], XmNtopShadowColor, ts); n++;
276     XtSetArg (args[n], XmNbottomShadowColor, bs); n++;
277     XtSetArg (args[n], XmNselectColor, white); n++;
278     XtSetArg (args[n], XmNarmColor, arm); n++;
279     XtSetArg (args[n], XmNtroughColor, arm); n++;
280     XtSetArg (args[n], XmNforeground, fg); n++;
281     SetAllChildrenOf (root, args, n);
282 
283 
284 #endif
285 
286     //
287     // Restore those DynamicResource settings which might have been affected
288     // by the change in modes.  Currently setting them all, but one day it may be more
289     // work than is necessary.  The settings in setResourceList might be touched
290     // by the SetAllChildrenOf call, i.e. XmNforeground which conflicts with
291     // the DynamicResource for Decorators.
292     //
293     if (this->setResourceList) {
294 	ListIterator it(*this->setResourceList);
295 	DynamicResource *dr;
296 	while ( (dr = (DynamicResource*)it.getNext()) ) {
297 	    dr->setData();
298 	}
299     }
300 }
301 
302 //
303 // walk the widget tree setting resources.
304 //
SetAllChildrenOf(Widget w,Arg * args,int n)305 void WorkSpaceComponent::SetAllChildrenOf (Widget w, Arg *args, int n)
306 {
307 Widget *kids, menu;
308 int nkids, i;
309 
310 
311     if ((XtIsSubclass (w, xmCascadeButtonWidgetClass))||
312 	(XtIsSubclass (w, xmCascadeButtonGadgetClass))) {
313 	menu = 0;
314 	XtVaGetValues (w, XmNsubMenuId, &menu, NULL);
315 	if (!menu) return ;
316 	XtSetValues (menu, args, n);
317 	SetAllChildrenOf (menu, args, n);
318     }
319     if (!XtIsComposite (w)) return ;
320 
321     XtVaGetValues (w, XmNchildren, &kids, XmNnumChildren, &nkids, NULL);
322     for (i=0; i<nkids; i++) {
323 	if (XtIsShell (kids[i])) continue ;
324 	XtSetValues (kids[i], args, n);
325 	SetAllChildrenOf (kids[i], args, n);
326     }
327 }
328 
329 //
330 // Determine if this Component is a node of the given class
331 //
isA(const char * classname)332 boolean WorkSpaceComponent::isA(const char *classname)
333 {
334     Symbol s = theSymbolManager->registerSymbol(classname);
335     return this->isA(s);
336 }
337 //
338 // Determine if this Component is of the given class.
339 //
isA(Symbol classname)340 boolean WorkSpaceComponent::isA(Symbol classname)
341 {
342     Symbol s = theSymbolManager->registerSymbol(ClassWorkSpaceComponent);
343     return (s == classname);
344 }
345 
346 
347 void
GetDimensions(Widget w,int * height,int * width)348 WorkSpaceComponent::GetDimensions(Widget w, int *height, int *width)
349 {
350 Dimension wdim, hdim;
351 
352     XtVaGetValues(w, XmNheight, &hdim, XmNwidth, &wdim, NULL);
353     *width = wdim; *height = hdim;
354 }
355 
installResizeHandler()356 void WorkSpaceComponent::installResizeHandler()
357 {
358     XmWorkspaceAddCallback(this->getRootWidget(), XmNresizingCallback,
359 	(XtCallbackProc)Component_ResizeCB, (XtPointer)this);
360 }
361 
Component_ResizeCB(Widget,XtPointer clientdata,XtPointer)362 extern "C" void Component_ResizeCB(Widget , XtPointer clientdata, XtPointer)
363 {
364     WorkSpaceComponent *wcs = (WorkSpaceComponent*) clientdata;
365     wcs->GetDimensions (wcs->getRootWidget() ,
366 	&wcs->userAssignedHeight, &wcs->userAssignedWidth);
367     wcs->resizeCB();
368     wcs->getNetwork()->setFileDirty();
369 }
370 
371 void
SetLabelResource(Widget w,const char * labelString)372 WorkSpaceComponent::SetLabelResource (Widget w, const char *labelString)
373 {
374     char        *filtered_string;
375     XmString    string;
376     XmFontList  xmfl;
377     Dimension   neww, newh;
378     XtWidgetGeometry req;
379     Dimension   mw,mh,mt,mb,ml,mr; // margin sizes
380     Dimension   ht,st; // thicknesses
381     Dimension   width, height;
382 
383     if (!labelString) return ;
384 
385 // FIXME: is it necessary to free the fontList acquired thru XtGetValues ?
386 
387     /*
388      * Replace "\n" character sequences with the '\n' character.
389      */
390     filtered_string = WorkSpaceComponent::FilterLabelString(labelString);
391     string = XmStringCreateLtoR((char*)filtered_string, "canvas");
392 
393     mw = mh = mt = mb = ml = mr = ht = st = 0;
394     XtVaGetValues (w, XmNfontList, &xmfl, XmNmarginWidth, &mw,
395 	XmNmarginHeight, &mh, XmNmarginWidth, &mw, XmNmarginHeight, &mh,
396 	XmNmarginLeft, &ml, XmNmarginRight, &mr, XmNmarginTop, &mt,
397 	XmNmarginBottom, &mb, XmNshadowThickness, &st, XmNhighlightThickness, &ht,
398 	XmNwidth, &width, XmNheight, &height, NULL);
399     XmStringExtent (xmfl, string, &neww, &newh);
400     req.width = neww + (2*(mw + ht + st)) + ml + mr;
401     req.height = newh + (2*(mh + ht + st)) + mt + mb;
402     req.request_mode = 0;
403     /*if (req.width > width)*/ req.request_mode|= CWWidth;
404     /*if (req.height > height)*/ req.request_mode|= CWHeight;
405     if (req.request_mode) XtMakeGeometryRequest (w, &req, NULL);
406     XtVaSetValues(w,XmNlabelString, string, NULL);
407 
408     XmStringFree(string);
409     delete filtered_string;
410 }
411 
412 //
413 // If there as never been an explicit size requested by the user, then
414 // return 0,0 so that the Motif's geometry mgmt will always provide the
415 // smallest necessary size.  If the user or cfg file did specify a size,
416 // then use the actual size.  Ironically, we never return the size the
417 // user explicitly made.
418 //
419 void
getXYSize(int * width,int * height)420 WorkSpaceComponent::getXYSize (int *width, int *height)
421 {
422 
423 #if USE_OWN_SIZES
424 int uw, uh;
425 int cw, ch;
426     this->getUserDimensions (&uw, &uh);
427     if (uw && uh)
428 	this->UIComponent::getXYSize (width, height);
429     else
430 	*width = *height = 0 ;
431 #else
432 	this->UIComponent::getXYSize (width, height);
433 #endif
434 }
435 
436 void
setVerticalLayout(boolean vertical)437 WorkSpaceComponent::setVerticalLayout (boolean vertical)
438 {
439     if (!this->acceptsLayoutChanges()) return ;
440     ASSERT (
441 	((this->currentLayout & WorkSpaceComponent::Vertical) !=
442 	(this->currentLayout & WorkSpaceComponent::Horizontal))
443 	||
444 	(this->currentLayout == WorkSpaceComponent::NotSet)
445     );
446 
447     if (vertical) {
448 	this->currentLayout&= ~WorkSpaceComponent::Horizontal;
449 	this->currentLayout|= WorkSpaceComponent::Vertical;
450     } else {
451 	this->currentLayout&= ~WorkSpaceComponent::Vertical;
452 	this->currentLayout|= WorkSpaceComponent::Horizontal;
453     }
454     this->getNetwork()->setFileDirty();
455 }
456 
457 boolean
verticallyLaidOut()458 WorkSpaceComponent::verticallyLaidOut()
459 {
460     if (this->currentLayout & WorkSpaceComponent::NotSet) return FALSE;
461 
462     return (this->currentLayout & WorkSpaceComponent::Vertical);
463 }
464 
465 
466 #if MIGHT_NEED_THIS_LATER
467 //
468 // Get the actual value which used to set some XmNresource.  This data would
469 // have started out as a null-terminated char* and been converted to a value
470 // thru some type convertor called from DynamicResource.  I think this function
471 // is not currently in use, but it's purpose is to enable copying resource values
472 // around.
473 //
474 void *
getResource(const char * res)475 WorkSpaceComponent::getResource (const char *res)
476 {
477 ListIterator it;
478 DynamicResource *dr;
479 
480     if (!this->setResourceList) return NUL(void *);
481 
482     it.setList (*this->setResourceList);
483     while (dr = (DynamicResource *)it.getNext()) {
484 	if (!strcmp (dr->getResourceName(), res)) {
485 	    break;
486 	}
487     }
488     if (!dr) return NUL(void*);
489 
490     return (void*)dr->getData();
491 }
492 #endif
493 
494 //
495 // Get the null-terminated char* which was used to set some XmNresource.
496 //
497 const char *
getResourceString(const char * res)498 WorkSpaceComponent::getResourceString (const char *res)
499 {
500 ListIterator it;
501 DynamicResource *dr;
502 
503     if (!this->setResourceList) return NUL(const char *);
504 
505     it.setList (*this->setResourceList);
506     while ( (dr = (DynamicResource *)it.getNext()) ) {
507         if (!strcmp (dr->getResourceName(), res)) {
508             break;
509         }
510     }
511     if (!dr) return NUL(const char*);
512     return (const char *)dr->getStringRepresentation();
513 }
514 
515 boolean
isResourceSet(const char * res)516 WorkSpaceComponent::isResourceSet (const char *res)
517 {
518 ListIterator it;
519 DynamicResource *dr;
520 
521     if (!this->setResourceList) return FALSE;
522 
523     it.setList (*this->setResourceList);
524     while ( (dr = (DynamicResource *)it.getNext()) ) {
525         if (!strcmp (dr->getResourceName(), res)) {
526 	    return TRUE;
527         }
528     }
529     return FALSE;
530 }
531 
532 //
533 // Copy my DynamicResource settings into someone else
534 //
transferResources(WorkSpaceComponent * wsc)535 void WorkSpaceComponent::transferResources (WorkSpaceComponent *wsc)
536 {
537     if (!this->setResourceList) return ;
538     if (!wsc->setResourceList)
539 	wsc->setResourceList = new List;
540 
541     ListIterator it (*this->setResourceList);
542     DynamicResource *dr;
543     while ( (dr = (DynamicResource*)it.getNext()) ) {
544 	wsc->setResourceList->appendElement((void*)dr);
545 	if (this->customPart) dr->setRootWidget(this->getRootWidget());
546 	else dr->setRootWidget(NUL(Widget));
547     }
548     this->setResourceList->clear();
549 }
550 
widgetDestroyed()551 void WorkSpaceComponent::widgetDestroyed ()
552 {
553     if (this->setResourceList) {
554 	ListIterator it (*this->setResourceList);
555 	DynamicResource *dr;
556 	while ( (dr = (DynamicResource*)it.getNext()) )
557 	    dr->setRootWidget(NUL(Widget));
558     }
559     this->UIComponent::widgetDestroyed ();
560 }
561 
562 //
563 // In addition to superclass work, we'll need to create new workspace
564 // lines since the start/end points of
565 // In the case of StandIn, using the superclass doesn't do any good
566 // since the widget is geometry-managed by the containing widget.  Setting
567 // XmN{x,y} has no effect.
568 //
setXYPosition(int x,int y)569 void WorkSpaceComponent::setXYPosition (int x, int y)
570 {
571     this->UIComponent::setXYPosition (x,y);
572     if (this->isManaged())
573 	XmWorkspaceSetLocation (this->getRootWidget(), x, y);
574 }
575 
576 //
577 // Store the this pointer in the widget's XmNuserData so that we
578 // can retrieve the Object in a callback in EditorWorkSpace.C
579 //
setRootWidget(Widget root,boolean standardDestroy)580 void WorkSpaceComponent::setRootWidget(Widget root, boolean standardDestroy)
581 {
582     this->UIComponent::setRootWidget(root, standardDestroy);
583     this->setLocalData(this);
584 }
585 
586 extern "C"  {
Component_motionEH(Widget w,XtPointer,XEvent * xev,Boolean * keep_going)587 void Component_motionEH
588 (Widget w, XtPointer , XEvent *xev, Boolean *keep_going)
589 {
590     *keep_going = True;
591     XtCallActionProc (w, "move_w", xev, NULL, 0);
592 }
Component_buttonReleaseEH(Widget w,XtPointer,XEvent * xev,Boolean * keep_going)593 void Component_buttonReleaseEH
594 (Widget w, XtPointer , XEvent *xev, Boolean *keep_going)
595 {
596     *keep_going = True;
597     if ((xev->xbutton.button != 1)&&(xev->xbutton.button != 2))
598 	return ;
599 
600     if ((xev->xbutton.button == 2) && (xev->xbutton.state & ShiftMask))
601 	return ;
602     XtCallActionProc (w, "release_w", xev, NULL, 0);
603 }
Component_buttonPressEH(Widget w,XtPointer,XEvent * xev,Boolean * keep_going)604 void Component_buttonPressEH
605 (Widget w, XtPointer , XEvent *xev, Boolean *keep_going)
606 {
607     *keep_going = True;
608     if ((xev->xbutton.button != 1)&&(xev->xbutton.button != 2))
609 	return ;
610 
611     if ((xev->xbutton.button == 2) && (xev->xbutton.state & ShiftMask))
612 	return ;
613     XtCallActionProc (w, "select_w", xev, NULL, 0);
614 }
615 } // extern C
616