1 /**
2  *
3  * $Header: /cvsroot/lesstif/lesstif/lib/Xm-2.1/CascadeBG.c,v 1.1 2004/08/28 19:22:43 dannybackx Exp $
4  *
5  * Copyright (C) 1995 Free Software Foundation, Inc.
6  * Copyright � 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 LessTif Development Team
7  *
8  * This file is part of the GNU LessTif Library.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public
21  * License along with this library; if not, write to the Free
22  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  **/
25 
26 static const char rcsid[] = "$Header: /cvsroot/lesstif/lesstif/lib/Xm-2.1/CascadeBG.c,v 1.1 2004/08/28 19:22:43 dannybackx Exp $";
27 
28 #include <LTconfig.h>
29 
30 #include <stdarg.h>
31 #include <string.h>
32 
33 #include <XmI/XmI.h>
34 #include <Xm/XmP.h>
35 #include <Xm/CacheP.h>
36 #include <Xm/CascadeB.h>	/* For XmCascadeButtonHighlight */
37 #include <Xm/CascadeBP.h>
38 #include <Xm/CascadeBGP.h>
39 #include <Xm/ManagerP.h>
40 #include <Xm/MenuShellP.h>
41 #include <Xm/RowColumnP.h>
42 #include <Xm/ScreenP.h>
43 #include <Xm/MenuUtilP.h>
44 
45 #include <XmI/DebugUtil.h>
46 
47 #define CASCADE_SPACING	4
48 
49 /* Forward Declarations */
50 
51 static void class_initialize(void);
52 
53 static void class_part_initialize(WidgetClass w_class);
54 
55 static void initialize(Widget request, Widget new_w,
56 		       ArgList args, Cardinal *num_args);
57 
58 static void resize(Widget w);
59 
60 static void destroy(Widget w);
61 
62 static void expose(Widget w, XEvent *event, Region region);
63 
64 static Boolean set_values(Widget current, Widget request, Widget new_w,
65 			  ArgList args, Cardinal *num_args);
66 
67 static void input_dispatch(Widget gadget, XEvent *event, Mask event_mask);
68 
69 static Boolean visual_change(Widget w, Widget parent, Widget n);
70 
71 static void secondary_object_create(Widget request, Widget new_w,
72 				    ArgList args, Cardinal *num_args);
73 
74 static void initialize_posthook(Widget request, Widget new_w,
75 				ArgList args, Cardinal *num_args);
76 
77 static Boolean set_values_prehook(Widget old, Widget request, Widget new_w,
78 				  ArgList args, Cardinal *num_args);
79 
80 static Boolean set_values_posthook(Widget old, Widget request, Widget new_w,
81 				   ArgList args, Cardinal *num_args);
82 
83 static void get_values_prehook(Widget new_w,
84 			       ArgList args, Cardinal *num_args);
85 
86 static void get_values_posthook(Widget new_w,
87 				ArgList args, Cardinal *num_args);
88 
89 static Cardinal get_sec_res_data(WidgetClass wc,
90 				 XmSecondaryResourceData **data);
91 
92 extern int _XmCascadeBCacheCompare(XtPointer A, XtPointer B);
93 
94 static void DelayedArm(Widget w, XEvent *event,
95 		       String *params, Cardinal *num_params);
96 
97 static void CheckDisarm(Widget w, XEvent *event,
98 			String *params, Cardinal *num_params);
99 
100 static void ArmAndActivate(Widget w, XEvent *event,
101 			   String *params, Cardinal *num_params);
102 
103 static void MenuProcEntry(int proc, Widget rc,...);
104 
105 static void CascadePopupHandler(XtPointer clientData, XtIntervalId *id);
106 
107 /*
108  * cache resources
109  */
110 #define Offset(field) XtOffsetOf(XmCascadeButtonGCacheObjRec, \
111 				 cascade_button_cache.field)
112 static XtResource cache_resources[] =
113 {
114     {
115 	XmNcascadePixmap, XmCPixmap, XmRGadgetPixmap,
116 	sizeof(Pixmap), Offset(cascade_pixmap),
117 	XmRImmediate, (XtPointer)XmUNSPECIFIED_PIXMAP
118     },
119     {
120 	XmNmappingDelay, XmCMappingDelay, XmRInt,
121 	sizeof(int), Offset(map_delay),
122 	XmRImmediate, (XtPointer)180
123     }
124 };
125 
126 XmCascadeButtonGCacheObjClassRec xmCascadeButtonGCacheObjClassRec = {
127     /* Object class part */
128     {
129 	/* superclass            */ (WidgetClass) &xmLabelGCacheObjClassRec,
130 	/* class_name            */ "XmCascadeButtonGCacheObjClass",
131 	/* widget_size           */ sizeof(XmCascadeButtonGCacheObjRec),
132 	/* class_initialize      */ NULL,
133 	/* class_part_initialize */ NULL,
134 	/* class_inited          */ False,
135 	/* initialize            */ NULL,
136 	/* initialize_hook       */ NULL,
137 	/* realize               */ NULL,
138 	/* actions               */ NULL,
139 	/* num_actions           */ 0,
140 	/* resources             */ cache_resources,
141 	/* num_resources         */ XtNumber(cache_resources),
142 	/* xrm_class             */ NULLQUARK,
143 	/* compress_motion       */ 0,
144 	/* compress_exposure     */ 0,
145 	/* compress_enterleave   */ 0,
146 	/* visible_interest      */ 0,
147 	/* destroy               */ NULL,
148 	/* resize                */ NULL,
149 	/* expose                */ NULL,
150 	/* set_values            */ NULL,
151 	/* set_values_hook       */ NULL,
152 	/* set_values_almost     */ NULL,
153 	/* get_values_hook       */ NULL,
154 	/* accept_focus          */ NULL,
155 	/* version               */ XtVersionDontCheck,
156 	/* callback offsets      */ NULL,
157 	/* tm_table              */ NULL,
158 	/* query_geometry        */ NULL,
159 	/* display_accelerator   */ NULL,
160 	/* extension             */ NULL
161     },
162     /* XmExtObject part */
163     {
164 	/* syn_resources      */ NULL,
165 	/* num_syn_resources  */ 0,
166 	/* extension          */ NULL
167     },
168     /* LabelGCacheObj part */
169     {
170 	/* foo                */ 0
171     },
172     /* CascadeButtonGCacheObj part */
173     {
174 	/* foo                */ 0
175     }
176 };
177 
178 /*
179  * Resources for the cascadebutton class
180  */
181 #undef Offset
182 #define Offset(field) XtOffsetOf(XmCascadeButtonGadgetRec, cascade_button.field)
183 #define GOffset(field) XtOffsetOf(XmCascadeButtonGadgetRec, gadget.field)
184 static XtResource resources[] = {
185     {
186 	XmNactivateCallback, XmCCallback, XmRCallback,
187 	sizeof(XtCallbackList), Offset(activate_callback),
188 	XmRCallback, (XtPointer)NULL
189     },
190     {
191 	XmNcascadingCallback, XmCCallback, XmRCallback,
192 	sizeof(XtCallbackList), Offset(cascade_callback),
193 	XmRCallback, (XtPointer)NULL
194     },
195     {
196 	XmNsubMenuId, XmCMenuWidget, XmRMenuWidget,
197 	sizeof(Widget), Offset(submenu),
198 	XmRMenuWidget, (XtPointer)NULL
199     },
200     /* resources we override from XmLabelGadget/XmGadget */
201     {
202 	XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension,
203 	sizeof(Dimension), GOffset(shadow_thickness),
204 	XmRImmediate, (XtPointer)2
205     },
206     {
207 	XmNtraversalOn, XmCTraversalOn, XmRBoolean,
208 	sizeof(Boolean), GOffset(traversal_on),
209 	XmRImmediate, (XtPointer)True
210     },
211     {
212 	XmNhighlightThickness, XmCHighlightThickness, XmRHorizontalDimension,
213 	sizeof(Dimension), GOffset(highlight_thickness),
214 	XmRImmediate, (XtPointer)2
215     },
216 };
217 
218 static XmBaseClassExtRec _XmCascadeBGRectClassExtRec = {
219     /* next_extension            */ NULL,
220     /* record_type               */ NULLQUARK,
221     /* version                   */ XmBaseClassExtVersion,
222     /* size                      */ sizeof(XmBaseClassExtRec),
223     /* initialize_prehook        */ XmInheritInitializePrehook,
224     /* set_values_prehook        */ set_values_prehook,
225     /* initialize_posthook       */ initialize_posthook,
226     /* set_values_posthook       */ set_values_posthook,
227     /* secondary_object_class    */ (WidgetClass)&xmCascadeButtonGCacheObjClassRec,
228     /* secondary_object_create   */ secondary_object_create,
229     /* get_secondary_resources   */ get_sec_res_data,
230     /* fast_subclass             */ { 0 },
231     /* get_values_prehook        */ get_values_prehook,
232     /* get_values_posthook       */ get_values_posthook,
233     /* class_part_init_prehook   */ NULL,
234     /* class_part_init_posthook  */ NULL,
235     /* ext_resources             */ NULL,
236     /* compiled_ext_resources    */ NULL,
237     /* num_ext_resources         */ 0,
238     /* use_sub_resources         */ False,
239     /* widget_navigable          */ XmInheritWidgetNavigable,
240     /* focus_change              */ XmInheritFocusChange,
241     /* wrapper_data              */ NULL
242 };
243 
244 static XmCacheClassPart cache_part = {
245     /* cache head part */
246     {
247 	/* next         */ NULL,
248 	/* prev         */ NULL,
249 	/* ref_count    */ 0
250     },
251     _XmCacheCopy,
252     _XmCacheDelete,
253     _XmCascadeBCacheCompare
254 };
255 
256 int _XmArrowPixmapCacheCompare(XtPointer A, XtPointer B);
257 
258 static XmCacheClassPart arrow_pixmap_cache = {
259     /* cache head part */
260     {
261 	/* next         */ NULL,
262 	/* prev         */ NULL,
263 	/* ref_count    */ 0
264     },
265     _XmCacheCopy,
266     _XmArrowPixmapCacheDelete,
267     _XmArrowPixmapCacheCompare
268 };
269 
270 static XmGadgetClassExtRec _XmCascadeBGGadgetClassExtRec = {
271     /* next_extension            */ NULL,
272     /* record_type               */ NULLQUARK,
273     /* version                   */ XmGadgetClassExtVersion,
274     /* size                      */ sizeof(XmGadgetClassExtRec),
275     /* widget_baseline_proc      */ XmInheritBaselineProc,
276     /* display_rect_proc         */ XmInheritDisplayRectProc,
277 #if XmVERSION >= 2
278     /* margins_proc              */ XmInheritMarginsProc,
279 #endif
280 };
281 
282 XmCascadeButtonGadgetClassRec xmCascadeButtonGadgetClassRec = {
283     /* RectObj class part */
284     {
285 	/* superclass            */ (WidgetClass) &xmLabelGadgetClassRec,
286 	/* class_name            */ "XmCascadeButtonGadget",
287 	/* widget_size           */ sizeof(XmCascadeButtonGadgetRec),
288 	/* class_initialize      */ class_initialize,
289 	/* class_part_initialize */ class_part_initialize,
290 	/* class_inited          */ False,
291 	/* initialize            */ initialize,
292 	/* initialize_hook       */ NULL,
293 	/* realize               */ NULL, /* FIX ME */
294 	/* actions               */ NULL,
295 	/* num_actions           */ 0,
296 	/* resources             */ resources,
297 	/* num_resources         */ XtNumber(resources),
298 	/* xrm_class             */ NULLQUARK,
299 	/* compress_motion       */ True,
300 	/* compress_exposure     */ XtExposeCompressMaximal,
301 	/* compress_enterleave   */ True,
302 	/* visible_interest      */ False,
303 	/* destroy               */ destroy,
304 	/* resize                */ resize,
305 	/* expose                */ expose,
306 	/* set_values            */ set_values,
307 	/* set_values_hook       */ NULL,
308 	/* set_values_almost     */ XtInheritSetValuesAlmost,
309 	/* get_values_hook       */ NULL,
310 	/* accept_focus          */ NULL,
311 	/* version               */ XtVersionDontCheck,
312 	/* callback offsets      */ NULL,
313 	/* tm_table              */ NULL,
314 	/* query_geometry        */ XtInheritQueryGeometry,
315 	/* display_accelerator   */ NULL,
316 	/* extension             */ (XtPointer)&_XmCascadeBGRectClassExtRec
317     },
318     /* XmGadget part */
319     {
320 	/* border_highlight   */ XmInheritBorderHighlight, /* FIX ME */
321 	/* border_unhighlight */ XmInheritBorderUnhighlight, /* FIX ME */
322 	/* arm_and_activate   */ ArmAndActivate,
323 	/* input_dispatch     */ input_dispatch,
324 	/* visual_change      */ visual_change,
325 	/* syn_resources      */ NULL,
326 	/* num_syn_resources  */ 0,
327 	/* cache_part         */ &cache_part,
328 	/* extension          */ (XtPointer)&_XmCascadeBGGadgetClassExtRec
329     },
330     /* XmLabelGadget part */
331     {
332 	/* setOverrideCallback */ XmInheritSetOverrideCallback,
333 	/* menuProcs           */ XmInheritMenuProc,
334 	/* extension           */ NULL
335     },
336     /* XmCascadeButtonGadget part */
337     {
338 	/* extension */ NULL
339     },
340 };
341 
342 
343 WidgetClass xmCascadeButtonGadgetClass =
344 				(WidgetClass)&xmCascadeButtonGadgetClassRec;
345 
346 /********************************* CACHE PART *******************************/
347 static void
secondary_object_create(Widget request,Widget new_w,ArgList args,Cardinal * num_args)348 secondary_object_create(Widget request, Widget new_w,
349 			ArgList args, Cardinal *num_args)
350 {
351     XmBaseClassExt *bce;
352     XtPointer nsec, rsec;
353     XmWidgetExtData ed;
354     Cardinal size;
355 
356     DEBUGOUT(_LtDebug(__FILE__, new_w,
357 		      "CascadeButtonGCacheRec %s being initialized.\n",
358 		      XtName(new_w)));
359 
360     bce = _XmGetBaseClassExtPtr(XtClass(new_w), XmQmotif);
361 
362     size = (*bce)->secondaryObjectClass->core_class.widget_size;
363     nsec = _XmExtObjAlloc(size);
364     rsec = _XmExtObjAlloc(size);
365 
366     ((XmExtRec *)nsec)->object.self = (Widget)nsec;
367     ((XmExtRec *)nsec)->object.widget_class = (*bce)->secondaryObjectClass;
368     ((XmExtRec *)nsec)->object.parent = XtParent(new_w);
369     ((XmExtRec *)nsec)->object.xrm_name = new_w->core.xrm_name;
370     ((XmExtRec *)nsec)->object.being_destroyed = False;
371     ((XmExtRec *)nsec)->object.destroy_callbacks = NULL;
372     ((XmExtRec *)nsec)->object.constraints = NULL;
373 
374     ExtObj_LogicalParent(nsec) = new_w;
375     ExtObj_ExtensionType(nsec) = XmCACHE_EXTENSION;
376 
377     XtGetSubresources(new_w, nsec, NULL, NULL,
378 		      (*bce)->secondaryObjectClass->core_class.resources,
379 		      (*bce)->secondaryObjectClass->core_class.num_resources,
380 		      args, *num_args);
381 
382     ed = (XmWidgetExtData)XtMalloc(sizeof(XmWidgetExtDataRec));
383     ed->widget = (Widget)nsec;
384     ed->reqWidget = (Widget)rsec;
385 
386     memcpy(rsec, nsec, size);
387 
388     ((XmExtRec *)rsec)->object.self = (Widget)rsec;
389 
390     _XmPushWidgetExtData(new_w, ed, XmCACHE_EXTENSION);
391 
392     LabG_Cache(new_w) = &(((XmLabelGCacheObject)nsec)->label_cache);
393     LabG_Cache(request) = &(((XmLabelGCacheObject)rsec)->label_cache);
394 
395     CBG_Cache(new_w) =
396 	&(((XmCascadeButtonGCacheObject)nsec)->cascade_button_cache);
397     CBG_Cache(request) =
398 	&(((XmCascadeButtonGCacheObject)rsec)->cascade_button_cache);
399 }
400 
401 int
_XmCascadeBCacheCompare(XtPointer A,XtPointer B)402 _XmCascadeBCacheCompare(XtPointer A, XtPointer B)
403 {
404     return !memcmp(((XmCascadeButtonGCacheObjPart *)A),
405 		 ((XmCascadeButtonGCacheObjPart *)B),
406 		 sizeof(XmCascadeButtonGCacheObjPart));
407 }
408 
409 int
_XmArrowPixmapCacheCompare(XtPointer A,XtPointer B)410 _XmArrowPixmapCacheCompare(XtPointer A, XtPointer B)
411 {
412     /* This will get confused by arrow direction and shadow thickness,
413      * which aren't defined in the XmArrowPixmap structure.
414      * But this is how M*tif defines it, so it's too late to do it right.
415      * This will seldom cause confusion, as arrow direction (based on string
416      * direction) is usually consistent throughout an application, and
417      * different shadow thicknesses imply different pixmap sizes (at least
418      * for the same size font).
419      */
420     return !memcmp(A, B, XtOffsetOf(XmArrowPixmap, pixmap));
421 }
422 
423 void
_XmArrowPixmapCacheDelete(XtPointer data)424 _XmArrowPixmapCacheDelete(XtPointer data)
425 {
426     XmGadgetCachePtr list;
427 
428     /* The pixmap alone isn't sufficient - the display should be passed.
429      * But this is how M*tif defines it...
430      */
431     if ((list = ClassCacheHead(&arrow_pixmap_cache).next))
432 	while (list != &ClassCacheHead(&arrow_pixmap_cache))
433 	{
434 	    if (((XmArrowPixmap *)CacheDataPtr(list))->pixmap == (Pixmap)data)
435 	    {
436 		if (!--list->ref_count)
437 		{
438 		    _XmFreeScratchPixmap((XmScreen)XmGetXmScreen(
439 			((XmArrowPixmap *)CacheDataPtr(list))->screen),
440 			(Pixmap)data);
441 		    list->prev->next = list->next;
442 		    list->next->prev = list->prev;
443 		    XtFree((char *)list);
444 		}
445 		return;
446 	    }
447 	    list = list->next;
448 	}
449 
450     _XmWarning(NULL, "_XmArrowPixmapCacheDelete: pixmap not in cache");
451 }
452 
453 static Dimension
default_font_height(XmFontList fl)454 default_font_height(XmFontList fl)
455 {
456 	XFontStruct *font;
457 	Dimension	fh;
458 
459 #ifdef	USE_XFT
460 	if (fl->renditions[0]->type == XmFONT_IS_XFT) {
461 		fh = fl->renditions[0]->xft_font->height;
462 		DEBUGOUT(_LtDebug(__FILE__, NULL, "DefaultFontHeight -> %d\n", fh));
463 		return fh;
464 	}
465 #endif
466 	fh = _XmFontListGetDefaultFont(fl, &font)
467 		? font->ascent + font->descent
468 		: 0;
469 	DEBUGOUT(_LtDebug(__FILE__, NULL, "DefaultFontHeight -> %d\n", fh));
470 	return fh;
471 }
472 
473 /* Assumes that the existing pixmaps are freed */
474 void
_XmCreateArrowPixmaps(Widget w)475 _XmCreateArrowPixmaps(Widget w)
476 {
477     Pixel ts, bs;
478     GC tgc, bgc, fgc;
479     XmFontList fl;
480     XmScreen sw;
481     XmArrowPixmap *cp, *acp;
482     Dimension st, th;
483     unsigned char sd;
484     XGCValues values;
485     XmArrowPixmap cpart;
486 
487     /* Get info from widget or gadget */
488     if (XmIsGadget(w))
489     {
490 	ts = XmParentTopShadowColor(w);
491 	bs = XmParentBottomShadowColor(w);
492 	values.foreground = XmParentBackground(w);
493 	tgc = XmParentTopShadowGC(w);
494 	bgc = XmParentBottomShadowGC(w);
495 	st = LabG_Shadow(w);
496 	sd = LabG_StringDirection(w);
497 	fl = LabG_Font(w);
498     }
499     else
500     {
501 	ts = Prim_TopShadowColor(w);
502 	bs = Prim_BottomShadowColor(w);
503 	values.foreground = CoreBackground(w);
504 	tgc = Prim_TopShadowGC(w);
505 	bgc = Prim_BottomShadowGC(w);
506 	st = Lab_Shadow(w);
507 	sd = Lab_StringDirection(w);
508 	fl = Lab_Font(w);
509     }
510 
511     /* Fill in the cache part template */
512     if (!(th = (default_font_height(fl) << 1) / 3))
513 	th = 1;
514     cpart.height = cpart.width = th + (st << 1);
515     cpart.foreground_color = values.foreground;
516     cpart.display = XtDisplay(w);
517     cpart.screen = XtScreen(w);
518     cpart.depth = DefaultDepthOfScreen(cpart.screen);
519     cpart.pixmap = XmUNSPECIFIED_PIXMAP;
520 
521     /* Get cache records for the normal and armed pixmaps */
522     cpart.top_shadow_color = ts;
523     cpart.bottom_shadow_color = bs;
524     cp = (XmArrowPixmap *)
525 	_XmCachePart(&arrow_pixmap_cache, (XtPointer)&cpart, sizeof cpart);
526 
527     cpart.top_shadow_color = bs;
528     cpart.bottom_shadow_color = ts;
529     acp = (XmArrowPixmap *)
530 	_XmCachePart(&arrow_pixmap_cache, (XtPointer)&cpart, sizeof cpart);
531 
532     /* If the cached pixmaps don't exist, create them */
533     if (cp->pixmap == XmUNSPECIFIED_PIXMAP
534 	|| acp->pixmap == XmUNSPECIFIED_PIXMAP)
535     {
536 	fgc = XtGetGC(w, GCForeground, &values);
537 	sw = (XmScreen)XmGetXmScreen(cpart.screen);
538 
539 	if (cp->pixmap == XmUNSPECIFIED_PIXMAP)
540 	{
541 	    cp->pixmap = _XmAllocScratchPixmap(sw, cpart.depth,
542 					       cpart.width, cpart.height);
543 	    XFillRectangle(cpart.display, cp->pixmap, fgc, 0, 0,
544 			   cpart.width, cpart.height);
545 
546 	    _XmDrawArrow(cpart.display, cp->pixmap, tgc, bgc, fgc,
547 			 st - 1, st - 1, th + 2, th + 2, st,
548 			 sd == XmSTRING_DIRECTION_L_TO_R
549 			 ? XmARROW_RIGHT : XmARROW_LEFT);
550 	}
551 
552 	if (acp->pixmap == XmUNSPECIFIED_PIXMAP)
553 	{
554 	    acp->pixmap = _XmAllocScratchPixmap(sw, cpart.depth,
555 					       cpart.width, cpart.height);
556 	    XFillRectangle(cpart.display, acp->pixmap, fgc, 0, 0,
557 			   cpart.width, cpart.height);
558 
559 	    _XmDrawArrow(cpart.display, acp->pixmap, bgc, tgc, fgc,
560 			 st - 1, st - 1, th + 2, th + 2, st,
561 			 sd == XmSTRING_DIRECTION_L_TO_R
562 			 ? XmARROW_RIGHT : XmARROW_LEFT);
563 	}
564 
565 	XtReleaseGC(w, fgc);
566     }
567 
568     /* Copy the cached pixmaps into the widget/gadget */
569     if (XmIsGadget(w))
570     {
571 	CBG_ArmedPixmap(w) = acp->pixmap;
572 	CBG_CascadePixmap(w) = cp->pixmap;
573     }
574     else
575     {
576 	CB_ArmedPixmap(w) = acp->pixmap;
577 	CB_CascadePixmap(w) = cp->pixmap;
578     }
579 }
580 
581 /******************************** GADGET PART *******************************/
582 static void
class_initialize(void)583 class_initialize(void)
584 {
585     XtResourceList combined, labels;
586     int ncom;
587     Cardinal nlabels;
588 
589     /* don't let the nulls fool you.  look at the header file -- the arg
590      * isn't used. */
591     ClassCacheHead(CBG_ClassCachePart(NULL)).prev =
592 	&ClassCacheHead(CBG_ClassCachePart(NULL));
593     ClassCacheHead(CBG_ClassCachePart(NULL)).next =
594 	&ClassCacheHead(CBG_ClassCachePart(NULL));
595 
596     _XmCascadeBGRectClassExtRec.record_type = XmQmotif;
597 
598     /*
599      * Label subclasses (ToggleBG, PushBG, CascadeBG) have a problem.  Since
600      * we do all the subpart manipulation in the pre- and post- hooks, and
601      * since those hooks aren't chained, we have to either make multiple
602      * calls to XtGetSubresources/Xt[Get|Set]Subvalues, or merge the resource
603      * lists.  Since I just wrote _XmTransformSubresources, seems like a
604      * waste not to use it.
605      */
606     ncom = XtNumber(cache_resources) +
607 	xmLabelGCacheObjClassRec.object_class.num_resources;
608 
609     _XmTransformSubResources(xmLabelGCacheObjClassRec.object_class.resources,
610 			   xmLabelGCacheObjClassRec.object_class.num_resources,
611 			     &labels, &nlabels);
612 
613     combined = (XtResourceList)XtMalloc(sizeof(XtResource) * ncom);
614 
615     memcpy(combined, labels, nlabels * sizeof(XtResource));
616     memcpy(&combined[nlabels],
617            cache_resources,
618  	   XtNumber(cache_resources) * sizeof(XtResource));
619 
620     XtFree((char *)labels);
621 
622     xmCascadeButtonGCacheObjClassRec.object_class.resources = combined;
623     xmCascadeButtonGCacheObjClassRec.object_class.num_resources = ncom;
624 }
625 
626 static void
class_part_initialize(WidgetClass widget_class)627 class_part_initialize(WidgetClass widget_class)
628 {
629     _XmFastSubclassInit(widget_class, XmCASCADE_BUTTON_GADGET_BIT);
630 }
631 
632 static void
initialize_posthook(Widget request,Widget new_w,ArgList args,Cardinal * num_args)633 initialize_posthook(Widget request, Widget new_w,
634 		    ArgList args, Cardinal *num_args)
635 {
636     XmWidgetExtData ext;
637 
638     DEBUGOUT(_LtDebug(__FILE__, new_w, "CascadeBG InitializePosthook\n"));
639 
640     /* don't let the null fool you */
641     LabG_Cache(new_w) = (XmLabelGCacheObjPart *)
642 	_XmCachePart(LabG_ClassCachePart(NULL),
643 		     (XtPointer)LabG_Cache(new_w),
644 		     sizeof(XmLabelGCacheObjPart));
645     CBG_Cache(new_w) = (XmCascadeButtonGCacheObjPart *)
646 	_XmCachePart(CBG_ClassCachePart(NULL),
647 		     (XtPointer)CBG_Cache(new_w),
648 		     sizeof(XmCascadeButtonGCacheObjPart));
649 
650     _XmPopWidgetExtData(new_w, &ext, XmCACHE_EXTENSION);
651 
652     _XmExtObjFree((XtPointer)ext->widget);
653     _XmExtObjFree((XtPointer)ext->reqWidget);
654 
655     XtFree((char *)ext);
656 }
657 
658 static void
place_cascade(Widget w)659 place_cascade(Widget w)
660 {
661     Position x;
662 
663     if (CBG_Submenu(w))
664     {
665 	CBG_Cascade_x(w) =
666 	    LabG_Highlight(w) + LabG_Shadow(w) + LabG_MarginWidth(w);
667 	if (LabG_StringDirection(w) == XmSTRING_DIRECTION_L_TO_R)
668 	    CBG_Cascade_x(w) =
669 		XtWidth(w) - CBG_Cascade_x(w) - CBG_Cascade_width(w);
670 
671 	CBG_Cascade_y(w) = (XtHeight(w) - CBG_Cascade_height(w)) / 2;
672 
673 	/* Make sure the label and cascade don't overlap */
674 
675 	if (LabG_StringDirection(w) == XmSTRING_DIRECTION_L_TO_R)
676 	{
677 	    x = CBG_Cascade_x(w) - CASCADE_SPACING - LabG_TextRect_width(w);
678 	    if (LabG_TextRect_x(w) > x)
679 		LabG_TextRect_x(w) = x;
680 	}
681 	else
682 	{
683 	    x = CBG_Cascade_x(w) + CBG_Cascade_width(w) + CASCADE_SPACING;
684 	    if (LabG_TextRect_x(w) < x)
685 		LabG_TextRect_x(w) = x;
686 	}
687     }
688     else
689     {
690     }
691 }
692 
693 static void
size_cascade(Widget w)694 size_cascade(Widget w)
695 {
696     int		dummy;
697     Window	dummyw;
698     unsigned	width, height;
699 
700     if (CBG_Submenu(w))
701     {
702 	if (CBG_CascadePixmap(w) > XmUNSPECIFIED_PIXMAP)
703 	{
704 	    XGetGeometry(XtDisplay(w), CBG_CascadePixmap(w),
705 			 &dummyw, &dummy, &dummy,
706 			 &width, &height, (unsigned *)&dummy, (unsigned *)&dummy);
707 	    CBG_Cascade_width(w) = width;
708 	    CBG_Cascade_height(w) = height;
709 	}
710 	else
711 	{
712 	    CBG_Cascade_width(w) = CBG_Cascade_height(w) =
713 		LabG_MenuType(w) == XmMENU_OPTION
714 		? default_font_height(LabG_Font(w)) + (LabG_Shadow(w) << 1)
715 		: 0;
716 	}
717     }
718     else
719     {
720 	CBG_Cascade_width(w) = 0;
721 	CBG_Cascade_height(w) = 0;
722     }
723 }
724 
725 static void
initialize(Widget request,Widget new_w,ArgList args,Cardinal * num_args)726 initialize(Widget request, Widget new_w,
727 	   ArgList args, Cardinal *num_args)
728 {
729     if (!XmIsManager(XtParent(new_w)))
730     {
731 	_XmError(new_w, "parent should be manager.");
732     }
733 
734     if (CBG_MapDelay(new_w) < 0)
735     {
736 	_XmWarning(new_w, "MappingDelay must be non-negative.");
737 	CBG_MapDelay(new_w) = 180;
738     }
739     if (CBG_Submenu(new_w) && (!XmIsRowColumn(CBG_Submenu(new_w)) ||
740 	(RC_Type(CBG_Submenu(new_w)) != XmMENU_PULLDOWN)))
741     {
742 	_XmWarning(new_w, "Submenu must a pull-down menu.");
743 	CBG_Submenu(new_w) = NULL;
744     }
745 
746     CBG_Cascade_x(new_w) = 0;
747     CBG_Cascade_y(new_w) = 0;
748     CBG_Cascade_width(new_w) = 0;
749     CBG_Cascade_height(new_w) = 0;
750 
751     CBG_SetArmed(new_w, False);
752     CBG_ArmedPixmap(new_w) = None;
753 
754     if (LabG_MenuType(new_w) == XmMENU_BAR ||
755 	LabG_MenuType(new_w) == XmMENU_POPUP ||
756 	LabG_MenuType(new_w) == XmMENU_PULLDOWN)
757     {
758 	G_TraversalOn(new_w) = True;
759 	LabG_Highlight(new_w) = 0;
760     }
761     else if (LabG_MenuType(new_w) != XmMENU_OPTION)
762     {
763 	_XmError(new_w, "Cascade gadget parent is incorrect type.");
764     }
765 
766     if (LabG_MenuType(new_w) == XmMENU_BAR)
767     {
768 	Dimension margin_width;
769 	XtResource resource =
770 	{
771 	    XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension,
772 	    sizeof(Dimension), 0,
773 	    XmRImmediate, (XtPointer)XmINVALID_DIMENSION
774 	};
775 
776 	/* Bend over backwards to see if the user didn't specify a marginWidth.
777 	 * Why doesn't this just use a default value like CascadeB does?
778 	 */
779 	XtGetSubresources(XtParent(new_w), &margin_width, XtName(new_w),
780 			  "XmCascadeButtonGCacheObjClass", &resource, 1,
781 			  args, *num_args);
782 	if (margin_width == (Dimension)XmINVALID_DIMENSION)
783 	    LabG_MarginWidth(new_w) = 6;
784     }
785 
786     else
787     {
788 	if (LabG_MenuType(new_w) != XmMENU_OPTION &&
789 	    CBG_CascadePixmap(new_w) == XmUNSPECIFIED_PIXMAP &&
790 	    CBG_Submenu(new_w))
791 	{
792 	    _XmCreateArrowPixmaps(new_w);
793 	}
794 	size_cascade(new_w);
795 
796 	if (CBG_Submenu(new_w))
797 	{
798 	    int margin;
799 
800 	    /* Make sure there's enough room on the side
801 	     * for the cascade pixmap.
802 	     */
803 	    margin = (CBG_Cascade_width(new_w) + CASCADE_SPACING)
804 		- (LabG_StringDirection(new_w) == XmSTRING_DIRECTION_L_TO_R
805 		   ? LabG_MarginRight(new_w) : LabG_MarginLeft(new_w));
806 	    if (margin > 0)
807 	    {
808 		if (LabG_StringDirection(new_w) == XmSTRING_DIRECTION_L_TO_R)
809 		    LabG_MarginRight(new_w) += margin;
810 		else
811 		{
812 		    LabG_MarginLeft(new_w) += margin;
813 		    LabG_TextRect_x(new_w) += margin;
814 		}
815 		if (!XtWidth(request))
816 		    XtWidth(new_w) += margin;
817 	    }
818 
819 	    /* Make sure there's enough room vertically */
820 	    margin = CBG_Cascade_height(new_w) - (LabG_TextRect_height(new_w)
821 						  + LabG_MarginTop(new_w)
822 						  + LabG_MarginBottom(new_w));
823 	    if (margin > 0)
824 	    {
825 		LabG_MarginTop(new_w) += margin >> 1;
826 		LabG_MarginBottom(new_w) += (margin + 1) >> 1;
827 		if (LabG_MenuType(new_w) != XmMENU_OPTION &&
828 		    !XtHeight(request))
829 		{
830 		    LabG_TextRect_y(new_w) += margin >> 1;
831 		    XtHeight(new_w) += margin;
832 		}
833 	    }
834 	}
835 
836 	place_cascade(new_w);
837     }
838 
839     if (CBG_Submenu(new_w))
840     {
841 	/* Make sure the RC also knows how to locate us */
842 	RC_MenuSubmenu(new_w);
843     }
844 
845     G_EventMask(new_w) = XmARM_EVENT | XmACTIVATE_EVENT |
846 	XmENTER_EVENT | XmLEAVE_EVENT |
847 	XmFOCUS_IN_EVENT | XmFOCUS_OUT_EVENT |
848 	XmHELP_EVENT | XmBDRAG_EVENT;
849 
850     CBG_Timer(new_w) = 0;
851     LabGClass_MenuProcs(XtClass(new_w)) = MenuProcEntry;
852 }
853 
854 static void
resize(Widget w)855 resize(Widget w)
856 {
857 #define superclass (&xmLabelGadgetClassRec)
858     (*superclass->rect_class.resize) (w);
859 #undef superclass
860 
861     if (LabG_MenuType(w) != XmMENU_BAR)
862     {
863 	place_cascade(w);
864     }
865 }
866 
867 static void
destroy(Widget w)868 destroy(Widget w)
869 {
870     if (CBG_Timer(w) != 0)
871     {
872 	XtRemoveTimeOut(CBG_Timer(w));
873 	CBG_Timer(w) = 0;
874     }
875 
876     if (CBG_ArmedPixmap(w))
877     {
878 	_XmArrowPixmapCacheDelete((XtPointer)CBG_ArmedPixmap(w));
879 	_XmArrowPixmapCacheDelete((XtPointer)CBG_CascadePixmap(w));
880     }
881 
882    _XmCacheDelete((XtPointer)CBG_Cache(w));
883 }
884 
885 static Boolean
set_values_prehook(Widget old,Widget request,Widget new_w,ArgList args,Cardinal * num_args)886 set_values_prehook(Widget old, Widget request, Widget new_w,
887 		   ArgList args, Cardinal *num_args)
888 {
889     XmBaseClassExt *bce;
890     XmWidgetExtData ed;
891     Cardinal size;
892     XtPointer nsec, rsec;
893 
894     bce = _XmGetBaseClassExtPtr(XtClass(new_w), XmQmotif);
895     size = (*bce)->secondaryObjectClass->core_class.widget_size;
896 
897     nsec = _XmExtObjAlloc(size);
898     rsec = _XmExtObjAlloc(size);
899 
900     ((XmExtRec *)nsec)->object.self = (Widget)nsec;
901     ((XmExtRec *)nsec)->object.widget_class = (*bce)->secondaryObjectClass;
902     ((XmExtRec *)nsec)->object.parent = XtParent(new_w);
903     ((XmExtRec *)nsec)->object.xrm_name = new_w->core.xrm_name;
904     ((XmExtRec *)nsec)->object.being_destroyed = False;
905     ((XmExtRec *)nsec)->object.destroy_callbacks = NULL;
906     ((XmExtRec *)nsec)->object.constraints = NULL;
907 
908     ExtObj_LogicalParent(nsec) = new_w;
909     ExtObj_ExtensionType(nsec) = XmCACHE_EXTENSION;
910 
911     memcpy(&((XmLabelGCacheObject)nsec)->label_cache,
912 	  LabG_Cache(new_w),
913 	  sizeof(XmLabelGCacheObjPart));
914     memcpy(&((XmCascadeButtonGCacheObject)nsec)->cascade_button_cache,
915            CBG_Cache(new_w),
916 	   sizeof(XmCascadeButtonGCacheObjPart));
917 
918     ed = (XmWidgetExtData)XtMalloc(sizeof(XmWidgetExtDataRec));
919 
920     ed->widget = (Widget)nsec;
921     ed->reqWidget = (Widget)rsec;
922 
923     _XmPushWidgetExtData(new_w, ed, XmCACHE_EXTENSION);
924 
925     _XmGadgetImportSecondaryArgs(new_w, args, num_args);
926 
927     XtSetSubvalues((XtPointer)nsec,
928 		   (*bce)->secondaryObjectClass->core_class.resources,
929 		   (*bce)->secondaryObjectClass->core_class.num_resources,
930 		   args, *num_args);
931 
932     memcpy(rsec, nsec, size);
933 
934     LabG_Cache(new_w) = &(((XmCascadeButtonGCacheObject)nsec)->label_cache);
935     LabG_Cache(request) = &(((XmCascadeButtonGCacheObject)rsec)->label_cache);
936 
937     CBG_Cache(new_w) =
938 	&(((XmCascadeButtonGCacheObject)nsec)->cascade_button_cache);
939     CBG_Cache(request) =
940 	&(((XmCascadeButtonGCacheObject)rsec)->cascade_button_cache);
941 
942     _XmExtImportArgs((Widget)nsec, args, num_args);
943 
944     return False;
945 }
946 
947 static Boolean
set_values_posthook(Widget old,Widget request,Widget new_w,ArgList args,Cardinal * num_args)948 set_values_posthook(Widget old, Widget request, Widget new_w,
949 		    ArgList args, Cardinal *num_args)
950 {
951     XmWidgetExtData ext;
952 
953     if (!_XmLabelCacheCompare((XtPointer)LabG_Cache(new_w),
954 			      (XtPointer)LabG_Cache(old)))
955     {
956 
957 	_XmCacheDelete((XtPointer)LabG_Cache(old));
958 
959 	LabG_Cache(new_w) = (XmLabelGCacheObjPart *)
960 	    _XmCachePart(LabG_ClassCachePart(NULL),
961 			 (XtPointer)LabG_Cache(new_w),
962 			 sizeof(XmLabelGCacheObjPart));
963     }
964     else
965     {
966 	LabG_Cache(new_w) = LabG_Cache(old);
967     }
968 
969     if (!_XmCascadeBCacheCompare((XtPointer)CBG_Cache(new_w),
970 				 (XtPointer)CBG_Cache(old)))
971     {
972 	_XmCacheDelete((XtPointer)CBG_Cache(old));
973 
974 	CBG_Cache(new_w) = (XmCascadeButtonGCacheObjPart *)
975 	    _XmCachePart(CBG_ClassCachePart(NULL),
976 			 (XtPointer)CBG_Cache(new_w),
977 			 sizeof(XmCascadeButtonGCacheObjPart));
978     }
979     else
980     {
981 	CBG_Cache(new_w) = CBG_Cache(old);
982     }
983 
984     _XmPopWidgetExtData(new_w, &ext, XmCACHE_EXTENSION);
985 
986     _XmExtObjFree((XtPointer)ext->widget);
987     _XmExtObjFree((XtPointer)ext->reqWidget);
988 
989     XtFree((char *)ext);
990 
991     return False;
992 }
993 
994 static Boolean
set_values(Widget old,Widget request,Widget new_w,ArgList args,Cardinal * num_args)995 set_values(Widget old, Widget request, Widget new_w,
996 	   ArgList args, Cardinal *num_args)
997 {
998     Boolean refresh_needed = False;
999 
1000     DEBUGOUT(_LtDebug(__FILE__, new_w, "set_values()\n"));
1001 
1002     if (CBG_MapDelay(new_w) < 0)
1003     {
1004 	_XmWarning(new_w, "MappingDelay must be non-negative.");
1005 	CBG_MapDelay(new_w) = CBG_MapDelay(old);
1006     }
1007     if (CBG_Submenu(new_w) && (!XmIsRowColumn(CBG_Submenu(new_w)) ||
1008 	(RC_Type(CBG_Submenu(new_w)) != XmMENU_PULLDOWN)))
1009     {
1010 	_XmWarning(new_w, "Submenu must a pull-down menu.");
1011 	CBG_Submenu(new_w) = CBG_Submenu(old);
1012     }
1013 
1014     if (LabG_MenuType(new_w) != XmMENU_OPTION)
1015     {
1016 	G_TraversalOn(new_w) = True;
1017 	LabG_Highlight(new_w) = 0;
1018     }
1019 
1020     if (CBG_CascadePixmap(old) != CBG_CascadePixmap(new_w) ||
1021 	(CBG_Submenu(new_w)
1022 	 ? CBG_CascadePixmap(new_w) == XmUNSPECIFIED_PIXMAP
1023 	 : CBG_ArmedPixmap(new_w)) ||
1024 	((CBG_ArmedPixmap(new_w) || (LabG_MenuType(new_w) == XmMENU_OPTION &&
1025 	  CBG_CascadePixmap(new_w) == XmUNSPECIFIED_PIXMAP)) &&
1026 	 LabG_Font(old) != LabG_Font(new_w)))
1027     {
1028 	if (CBG_ArmedPixmap(old))
1029 	{
1030 	    _XmArrowPixmapCacheDelete((XtPointer)CBG_CascadePixmap(old));
1031 	    _XmArrowPixmapCacheDelete((XtPointer)CBG_ArmedPixmap(old));
1032 	    if (CBG_CascadePixmap(old) == CBG_CascadePixmap(new_w))
1033 		CBG_CascadePixmap(new_w) = XmUNSPECIFIED_PIXMAP;
1034 	    CBG_ArmedPixmap(new_w) = None;
1035 	}
1036 	if (LabG_MenuType(new_w) != XmMENU_BAR)
1037 	{
1038 	    if (LabG_MenuType(new_w) != XmMENU_OPTION &&
1039 		CBG_CascadePixmap(new_w) == XmUNSPECIFIED_PIXMAP &&
1040 		CBG_Submenu(new_w))
1041 	    {
1042 		_XmCreateArrowPixmaps(new_w);
1043 	    }
1044 	    size_cascade(new_w);
1045 	    refresh_needed = True;
1046 	}
1047     }
1048 
1049     if (XtSensitive(new_w) != XtSensitive(old))
1050     {
1051 	refresh_needed = True;
1052     }
1053 
1054     if (CBG_Submenu(old) != CBG_Submenu(new_w))
1055     {
1056 	/* Make sure the RC also knows how to locate us */
1057 	RC_MenuSubmenu(new_w);
1058     }
1059 
1060     /* Adjust margins for the cascade pixmap size if necessary.
1061      * Margins be increased or decreased; if the margin was explicitly set
1062      * in this call, don't decrease it past that (though it can get bigger).
1063      */
1064     if (LabG_MenuType(new_w) != XmMENU_BAR &&
1065 	(CBG_Cascade_width(new_w) != CBG_Cascade_width(old)
1066 	 || CBG_Cascade_height(new_w) != CBG_Cascade_height(old)
1067 	 || LabG_StringDirection(new_w) != LabG_StringDirection(old)
1068 	 || (LabG_StringDirection(new_w) == XmSTRING_DIRECTION_L_TO_R
1069 	     ? LabG_MarginRight(new_w) != LabG_MarginRight(old)
1070 	     : LabG_MarginLeft(new_w) != LabG_MarginLeft(old))
1071 	 || LabG_MarginTop(new_w) != LabG_MarginTop(old)
1072 	 || LabG_MarginBottom(new_w) != LabG_MarginBottom(old)))
1073     {
1074 	int margin, tm, bm;
1075 
1076 	margin = CBG_Cascade_width(new_w) + CASCADE_SPACING
1077 	    - (LabG_StringDirection(new_w) == XmSTRING_DIRECTION_L_TO_R
1078 	       ? LabG_MarginRight(new_w) : LabG_MarginLeft(new_w));
1079 	if (margin && (margin > 0 ||
1080 	    (LabG_StringDirection(new_w) == XmSTRING_DIRECTION_L_TO_R
1081 	     ? LabG_MarginRight(new_w) == LabG_MarginRight(old)
1082 	     : LabG_MarginLeft(new_w) == LabG_MarginLeft(old))))
1083 	{
1084 	    if (LabG_StringDirection(new_w) == XmSTRING_DIRECTION_L_TO_R)
1085 		LabG_MarginRight(new_w) += margin;
1086 	    else
1087 	    {
1088 		LabG_MarginLeft(new_w) += margin;
1089 		LabG_TextRect_x(new_w) += margin;
1090 	    }
1091 	    if (LabG_RecomputeSize(new_w) || !XtWidth(request))
1092 		XtWidth(new_w) += margin;
1093 	}
1094 
1095 	margin = CBG_Cascade_height(new_w) - (LabG_TextRect_height(new_w)
1096 					      + LabG_MarginTop(new_w)
1097 					      + LabG_MarginBottom(new_w));
1098 	if (margin)
1099 	{
1100 	    tm = margin / 2;
1101 	    if (tm < (LabG_MarginTop(new_w) == LabG_MarginTop(old)
1102 		      ? XmDEFAULT_TOP_MARGIN - (int)LabG_MarginTop(new_w)
1103 		      : 0))
1104 		tm = (LabG_MarginTop(new_w) == LabG_MarginTop(old)
1105 		      ? XmDEFAULT_TOP_MARGIN - (int)LabG_MarginTop(new_w)
1106 		      : 0);
1107 	    LabG_MarginTop(new_w) += tm;
1108 	    if (LabG_MenuType(new_w) != XmMENU_OPTION &&
1109 		(LabG_RecomputeSize(new_w) || !XtHeight(request)))
1110 		XtHeight(new_w) += tm;
1111 
1112 	    bm = (margin + 1) / 2;
1113 	    if (bm < (LabG_MarginBottom(new_w) == LabG_MarginBottom(old)
1114 		      ? XmDEFAULT_BOTTOM_MARGIN - (int)LabG_MarginBottom(new_w)
1115 		      : 0))
1116 		bm = (LabG_MarginBottom(new_w) == LabG_MarginBottom(old)
1117 		      ? XmDEFAULT_BOTTOM_MARGIN - (int)LabG_MarginBottom(new_w)
1118 		      : 0);
1119 	    LabG_MarginBottom(new_w) += bm;
1120 	    if (LabG_RecomputeSize(new_w) || !XtHeight(request))
1121 		XtHeight(new_w) += bm;
1122 
1123 	    if (tm != bm)
1124 		LabG_TextRect_y(new_w) += (tm - bm) / 2;
1125 	}
1126 
1127 	refresh_needed = True;
1128     }
1129 
1130     if (LabG_MenuType(new_w) != XmMENU_BAR &&
1131 	(CBG_Cascade_width(new_w) != CBG_Cascade_width(old)
1132 	 || CBG_Cascade_height(new_w) != CBG_Cascade_height(old)
1133 	 || LabG_Shadow(new_w) != LabG_Shadow(old)
1134 	 || LabG_MarginWidth(new_w) != LabG_MarginWidth(old)
1135 	 || LabG_TextRect_y(new_w) != LabG_TextRect_y(old)
1136 	 || LabG_TextRect_height(new_w) != LabG_TextRect_height(old)
1137 	 || LabG_StringDirection(new_w) != LabG_StringDirection(old)))
1138     {
1139 	Dimension width, height;
1140 
1141 	width = XtWidth(new_w);
1142 	height = XtHeight(new_w);
1143 	XtWidth(new_w) = XtWidth(old);
1144 	XtHeight(new_w) = XtHeight(old);
1145 	place_cascade(new_w);
1146 	XtWidth(new_w) = width;
1147 	XtHeight(new_w) = height;
1148 	refresh_needed = True;
1149     }
1150 
1151     return refresh_needed;
1152 }
1153 
1154 static void
get_values_prehook(Widget new_w,ArgList args,Cardinal * num_args)1155 get_values_prehook(Widget new_w, ArgList args, Cardinal *num_args)
1156 {
1157     XmBaseClassExt *bce;
1158     XmWidgetExtData ed;
1159     Cardinal size;
1160     XtPointer nsec;
1161 
1162     bce = _XmGetBaseClassExtPtr(XtClass(new_w), XmQmotif);
1163     size = (*bce)->secondaryObjectClass->core_class.widget_size;
1164 
1165     nsec = _XmExtObjAlloc(size);
1166 
1167     memcpy(&((XmLabelGCacheObject)nsec)->label_cache,
1168            LabG_Cache(new_w),
1169 	   sizeof(XmLabelGCacheObjPart));
1170     memcpy(&((XmCascadeButtonGCacheObject)nsec)->cascade_button_cache,
1171            CBG_Cache(new_w),
1172 	   sizeof(XmCascadeButtonGCacheObjPart));
1173 
1174     /*
1175      * don't do this and ResInd will blow up.
1176      */
1177     ((XmExtRec *)nsec)->object.self = (Widget)nsec;
1178     ((XmExtRec *)nsec)->object.widget_class = (*bce)->secondaryObjectClass;
1179     ((XmExtRec *)nsec)->object.parent = XtParent(new_w);
1180     ((XmExtRec *)nsec)->object.xrm_name = new_w->core.xrm_name;
1181     ((XmExtRec *)nsec)->object.being_destroyed = False;
1182     ((XmExtRec *)nsec)->object.destroy_callbacks = NULL;
1183     ((XmExtRec *)nsec)->object.constraints = NULL;
1184 
1185     ExtObj_LogicalParent(nsec) = new_w;
1186     ExtObj_ExtensionType(nsec) = XmCACHE_EXTENSION;
1187 
1188     ed = (XmWidgetExtData)XtMalloc(sizeof(XmWidgetExtDataRec));
1189     ed->widget = (Widget)nsec;
1190 
1191     _XmPushWidgetExtData(new_w, ed, XmCACHE_EXTENSION);
1192 
1193     XtGetSubvalues((XtPointer)nsec,
1194 		   (*bce)->secondaryObjectClass->core_class.resources,
1195 		   (*bce)->secondaryObjectClass->core_class.num_resources,
1196 		   args, *num_args);
1197 
1198     _XmExtGetValuesHook((Widget)nsec, args, num_args);
1199 }
1200 
1201 static void
get_values_posthook(Widget new_w,ArgList args,Cardinal * num_args)1202 get_values_posthook(Widget new_w, ArgList args, Cardinal *num_args)
1203 {
1204     XmWidgetExtData ext;
1205 
1206     _XmPopWidgetExtData(new_w, &ext, XmCACHE_EXTENSION);
1207 
1208     _XmExtObjFree((XtPointer)ext->widget);
1209 
1210     XtFree((char *)ext);
1211 }
1212 
1213 
1214 static void
draw_cascade(Widget w)1215 draw_cascade(Widget w)
1216 {
1217     Pixmap pm;
1218 
1219     if (CBG_IsArmed(w) || LabG_MenuType(w) == XmMENU_OPTION)
1220     {
1221 	_XmDrawShadows(XtDisplay(w), XtWindow(w),
1222 		       XmParentTopShadowGC(w), XmParentBottomShadowGC(w),
1223 		       XtX(w) + LabG_Highlight(w), XtY(w) + LabG_Highlight(w),
1224 		       XtWidth(w) - (LabG_Highlight(w) << 1),
1225 		       XtHeight(w) - (LabG_Highlight(w) << 1),
1226 		       LabG_Shadow(w), XmSHADOW_OUT);
1227     }
1228 
1229     pm = CBG_IsArmed(w) && CBG_ArmedPixmap(w) > XmUNSPECIFIED_PIXMAP
1230 	? CBG_ArmedPixmap(w)
1231 	: CBG_CascadePixmap(w);
1232     if (pm > XmUNSPECIFIED_PIXMAP)
1233     {
1234 	XCopyArea(XtDisplay(w), pm, XtWindow(w),
1235 		  LabG_NormalGC(w),
1236 		  0, 0,
1237 		  CBG_Cascade_width(w), CBG_Cascade_height(w),
1238 		  XtX(w) + CBG_Cascade_x(w), XtY(w) + CBG_Cascade_y(w));
1239     }
1240     else if (pm == XmUNSPECIFIED_PIXMAP && LabG_MenuType(w) == XmMENU_OPTION && CBG_Submenu(w))
1241     {
1242 	Dimension width, height, ch;
1243 
1244 	/* Base the rectangle cascade on the text height,
1245 	 * but for bigger text, it gets successively squatter.
1246 	 */
1247 	width = CBG_Cascade_width(w) - 3;
1248 	height = (LabG_Shadow(w) << 1) + 1;
1249 	ch = CBG_Cascade_height(w) - height;
1250 	if (ch >= 13)
1251 	{
1252 	    width -= 3;
1253 	    height += 3;
1254 	}
1255 	else if (ch >= 9)
1256 	{
1257 	    width -= 2;
1258 	    height += 2;
1259 	}
1260 	else if (ch >= 6)
1261 	{
1262 	    width--;
1263 	    height++;
1264 	}
1265 	_XmDrawShadows(XtDisplay(w), XtWindow(w),
1266 		       XmParentTopShadowGC(w), XmParentBottomShadowGC(w),
1267 		       XtX(w) + CBG_Cascade_x(w),
1268 		       XtY(w) + CBG_Cascade_y(w) +
1269 			((CBG_Cascade_height(w) - height) >> 1),
1270 		       width, height, LabG_Shadow(w), XmSHADOW_OUT);
1271     }
1272 }
1273 
1274 static void
expose(Widget w,XEvent * event,Region region)1275 expose(Widget w,
1276        XEvent *event,
1277        Region region)
1278 {
1279     DEBUGOUT(_LtDebug(__FILE__, w, "expose() Armed(%d) type %s\n",
1280 		      CBG_IsArmed(w), _LtDebugMenuType2String(LabG_MenuType(w))));
1281 
1282     draw_cascade(w);
1283 
1284 #define superclass (&xmLabelGadgetClassRec)
1285     (*superclass->rect_class.expose) (w, event, region);
1286 #undef superclass
1287 }
1288 
1289 static Cardinal
get_sec_res_data(WidgetClass wc,XmSecondaryResourceData ** data)1290 get_sec_res_data(WidgetClass wc, XmSecondaryResourceData **data)
1291 {
1292     /* FIX ME */
1293 
1294     return _XmSecondaryResourceData(&_XmCascadeBGRectClassExtRec,
1295 				    data, NULL, NULL, NULL, NULL);
1296 }
1297 
1298 static void
DoSelect(Widget w,XEvent * event,String * params,Cardinal * num_params)1299 DoSelect(Widget w, XEvent *event, String *params, Cardinal *num_params)
1300 {
1301 Boolean validButton;
1302 
1303     DEBUGOUT(_LtDebug(__FILE__, w, "%s:DoSelect(%d)\n\t%s posted mine %s\n",
1304 	__FILE__, __LINE__,
1305 	RC_PopupPosted(XtParent(w)) ? XtName(RC_PopupPosted(XtParent(w))) : "nothing",
1306 	CBG_Submenu(w) ? XtName(CBG_Submenu(w)) : "none"
1307 	));
1308     DEBUGOUT(_LtDebug("MENU", w, "%s:DoSelect(%d)\n\t%s posted mine %s %s\n",
1309 	__FILE__, __LINE__,
1310 	RC_PopupPosted(XtParent(w)) ? XtName(RC_PopupPosted(XtParent(w))) : "nothing",
1311 	CBG_Submenu(w) ? XtName(CBG_Submenu(w)) : "none",
1312 	event ? _LtDebugEventType2String(event->xany.type) : "no-event"
1313 	));
1314     if (event && event->xany.type == ButtonRelease)
1315     {
1316 	RC_MenuButton(w, event, &validButton);
1317     }
1318     else
1319     {
1320 	validButton = True;
1321     }
1322     if (validButton)
1323     {
1324 	XAllowEvents(XtDisplay(w), SyncPointer, CurrentTime);
1325 	_XmMenuFocus(XtParent(w), XmMENU_FOCUS_SET, CurrentTime);
1326 	if (CBG_Submenu(w))
1327 	{
1328 	    if (RC_PopupPosted(XtParent(w)) != CBG_Submenu(w))
1329 	    {
1330 		_XmCascadingPopup(w, event, True);
1331 	    }
1332 
1333 	    RCClass_MenuTraverse(CBG_Submenu(w), XmTRAVERSE_HOME);
1334 
1335 	    _XmSetInDragMode(w, False);
1336 	}
1337 	else
1338 	{
1339 	XmAnyCallbackStruct cbs;
1340 
1341 	    cbs.reason = XmCR_ACTIVATE;
1342 	    cbs.event = event;
1343 	    if (XmIsRowColumn(XtParent(w)))
1344 	    {
1345 		RC_MenuMenuCallback(w, &cbs);
1346 	    }
1347 	    if (!LabG_SkipCallback(w) && CBG_ActivateCall(w))
1348 	    {
1349 		XFlush(XtDisplay(w));
1350 
1351 		XtCallCallbackList(w, CBG_ActivateCall(w), &cbs);
1352 	    }
1353 	    XmCascadeButtonGadgetHighlight(w, False);
1354 	    if (RC_PopupPosted(XtParent(w)))
1355 	    {
1356 	    Boolean poppedUp;
1357 
1358 		RC_MenuShellPopdown(w, event, &poppedUp);
1359 	    }
1360 	}
1361     }
1362 }
1363 
1364 static void
MenuBarSelect(Widget w,XEvent * event,String * params,Cardinal * num_params)1365 MenuBarSelect(Widget w, XEvent *event, String *params, Cardinal *num_params)
1366 {
1367     Boolean validButton;
1368 
1369     DEBUGOUT(_LtDebug(__FILE__, w, "%s:MenuBarSelect(%d)\n\t%s posted mine %s\n",
1370 	__FILE__, __LINE__,
1371 	RC_PopupPosted(XtParent(w)) ? XtName(RC_PopupPosted(XtParent(w))) : "nothing",
1372 	CBG_Submenu(w) ? XtName(CBG_Submenu(w)) : "none"
1373 	));
1374     DEBUGOUT(_LtDebug("MENU", w, "%s:MenuBarSelect(%d)\n\t%s posted mine %s\n",
1375 	__FILE__, __LINE__,
1376 	RC_PopupPosted(XtParent(w)) ? XtName(RC_PopupPosted(XtParent(w))) : "nothing",
1377 	CBG_Submenu(w) ? XtName(CBG_Submenu(w)) : "none"
1378 	));
1379     if (event && event->xany.type == ButtonPress)
1380     {
1381 	RC_MenuButton(w, event, &validButton);
1382     }
1383     else
1384     {
1385 	validButton = True;
1386     }
1387     if (validButton)
1388     {
1389 	XAllowEvents(XtDisplay(w), SyncPointer, CurrentTime);
1390 	XmProcessTraversal(w, XmTRAVERSE_CURRENT);
1391 	if (RC_PopupPosted(XtParent(w)))
1392 	{
1393 	Cardinal i;
1394 
1395 	    for (i = 0; i < MGR_NumChildren(RC_PopupPosted(XtParent(w))); i++)
1396 	    {
1397 	    Widget w1 = MGR_Children(RC_PopupPosted(XtParent(w)))[i];
1398 
1399 		_XmMenuDisarmItem(w1);
1400 	    }
1401 	    if (RC_PopupPosted(XtParent(w)) != CBG_Submenu(w))
1402 	    {
1403 	    Boolean poppedUp;
1404 
1405 		RC_MenuShellPopdown(w, event, &poppedUp);
1406 	    }
1407 	    else if (CBG_Submenu(w) && RC_PopupPosted(CBG_Submenu(w)))
1408 	    {
1409 	    Boolean poppedUp;
1410 
1411 		RC_MenuShellPopdown(RC_CascadeBtn(RC_PopupPosted(CBG_Submenu(w))), event, &poppedUp);
1412 	    }
1413 	}
1414 	XmCascadeButtonGadgetHighlight(w, True);
1415 	MGR_ActiveChild(XtParent(w)) = w;
1416 
1417 	RCClass_MenuProcs(XtClass(XtParent(w)))(XmMENU_ARM, XtParent(w), NULL);
1418 
1419 	if (RC_PopupPosted(XtParent(w)) != CBG_Submenu(w))
1420 	{
1421 	    _XmCascadingPopup(w, event, True);
1422 	}
1423 	_XmSetInDragMode(w, True);
1424     }
1425 }
1426 
1427 static void
ArmAndPost(Widget w,XEvent * event,String * params,Cardinal * num_params)1428 ArmAndPost(Widget w, XEvent *event, String *params, Cardinal *num_params)
1429 {
1430     DEBUGOUT(_LtDebug(__FILE__, w, "ArmAndPost(): %p %p\n", w, CBG_Submenu(w)));
1431     DEBUGOUT(_LtDebug("MENU", w, "%s:ArmAndPost(%d)\n\t%s posted mine %s\n",
1432 	__FILE__, __LINE__,
1433 	RC_PopupPosted(XtParent(w)) ? XtName(RC_PopupPosted(XtParent(w))) : "nothing",
1434 	CBG_Submenu(w) ? XtName(CBG_Submenu(w)) : "none"
1435 	));
1436 
1437     XmProcessTraversal(w, XmTRAVERSE_CURRENT);
1438 
1439 #if 0
1440     if (!RC_IsArmed(CBG_Submenu(w)))
1441     {
1442 	DEBUGOUT(_LtDebug(__FILE__, w, "MENU_ARM\n"));
1443 
1444 	RCClass_MenuProcs(XtClass(XtParent(w)))(XmMENU_ARM, XtParent(w), NULL);
1445     }
1446 
1447     _XmCascadingPopup(w, event, True);
1448     _XmSetInDragMode(w, True);
1449 #else
1450     XmCascadeButtonGadgetHighlight(w, True);
1451     MGR_ActiveChild(XtParent(w)) = w;
1452     RCClass_MenuProcs(XtClass(XtParent(w)))(XmMENU_ARM, XtParent(w), NULL);
1453     _XmCascadingPopup(w, event, True);
1454     _XmSetInDragMode(w, True);
1455 #endif
1456 }
1457 
1458 static void
MenuBarEnter(Widget w,XEvent * event,String * params,Cardinal * num_params)1459 MenuBarEnter(Widget w, XEvent *event, String *params, Cardinal *num_params)
1460 {
1461     DEBUGOUT(_LtDebug(__FILE__, w, "MenuBarEnter\n\t%s %s %s %s posted posting %s\n",
1462 	_XmGetInDragMode(w) ? "Dragging" : "Not Dragging",
1463 	_LtDebugRcType2String(LabG_MenuType(w)),
1464 	RC_IsArmed(XtParent(w)) ? "Armed" : "Not Armed",
1465 	RC_PopupPosted(XtParent(w)) ? XtName(RC_PopupPosted(XtParent(w))) : "nothing",
1466 	CBG_Submenu(w) ? XtName(CBG_Submenu(w)) : "nothing"
1467 	));
1468     DEBUGOUT(_LtDebug("MENU", w, "MenuBarEnter\n\t%s %s %s %s posted posting %s\n",
1469 	_XmGetInDragMode(w) ? "Dragging" : "Not Dragging",
1470 	_LtDebugRcType2String(LabG_MenuType(w)),
1471 	RC_IsArmed(XtParent(w)) ? "Armed" : "Not Armed",
1472 	RC_PopupPosted(XtParent(w)) ? XtName(RC_PopupPosted(XtParent(w))) : "nothing",
1473 	CBG_Submenu(w) ? XtName(CBG_Submenu(w)) : "nothing"
1474 	));
1475 
1476     if (_XmGetInDragMode(w))
1477     {
1478 	if (LabG_MenuType(w) == XmMENU_BAR)
1479 	{
1480 	    if (RC_IsArmed(XtParent(w)))
1481 	    {
1482 		if (CBG_Submenu(w))
1483 		{
1484 		    if (RC_PopupPosted(XtParent(w)) && RC_PopupPosted(XtParent(w)) != CBG_Submenu(w))
1485 		    {
1486 			_XmCascadingPopup(w, event, False);
1487 		    }
1488 		    if (RC_PopupPosted(XtParent(w)) && RC_PopupPosted(XtParent(w)) != CBG_Submenu(w))
1489 		    {
1490 		    Boolean poppedUp;
1491 
1492 			RC_MenuShellPopdown(w, event, &poppedUp);
1493 		    }
1494 		    XmCascadeButtonGadgetHighlight(w, True);
1495 		    if (!RC_PopupPosted(XtParent(w)))
1496 		    {
1497 			RC_MenuCascading(w, event);
1498 		    }
1499 		}
1500 		else
1501 		{
1502 		    _XmCascadingPopup(w, event, True);
1503 		    if (RC_PopupPosted(XtParent(w)) && RC_PopupPosted(XtParent(w)) != CBG_Submenu(w))
1504 		    {
1505 		    Boolean poppedUp;
1506 
1507 			RC_MenuShellPopdown(w, event, &poppedUp);
1508 		    }
1509 		    XmCascadeButtonGadgetHighlight(w, True);
1510 		}
1511 	    }
1512 	}
1513 	else
1514 	{
1515 	    _XmWarning(w, "%s(%d) - MenuBarEnter not in MenuBar",
1516 		__FILE__, __LINE__);
1517 	}
1518     }
1519 }
1520 
1521 static void
MenuBarLeave(Widget w,XEvent * event,String * params,Cardinal * num_params)1522 MenuBarLeave(Widget w, XEvent *event, String *params, Cardinal *num_params)
1523 {
1524     if (_XmGetInDragMode(w))
1525     {
1526 	if (LabG_MenuType(w) == XmMENU_BAR)
1527 	{
1528 	    if (RC_IsArmed(XtParent(w)))
1529 	    {
1530 		if (!CBG_Submenu(w) || (RC_PopupPosted(XtParent(w)) && RC_PopupPosted(XtParent(w)) != CBG_Submenu(w)))
1531 		{
1532 		    XmCascadeButtonGadgetHighlight(w, False);
1533 		}
1534 	    }
1535 	}
1536 	else
1537 	{
1538 	    _XmWarning(w, "%s(%d) - MenuBarLeave not in MenuBar",
1539 		__FILE__, __LINE__);
1540 	}
1541     }
1542 }
1543 
1544 static void
StartDrag(Widget w,XEvent * event,String * params,Cardinal * num_params)1545 StartDrag(Widget w, XEvent *event, String *params, Cardinal *num_params)
1546 {
1547     Boolean validButton;
1548     Boolean poppedUp;
1549 
1550     DEBUGOUT(_LtDebug(__FILE__, w, "StartDrag()\n"));
1551 
1552     XAllowEvents(XtDisplay(w), SyncPointer, CurrentTime);
1553 
1554     _XmRecordEvent(event);
1555 
1556     /* Is it even the right kind of event? */
1557     if (!event || event->type != ButtonPress)
1558     {
1559 	return;
1560     }
1561 
1562     /* If the submenu is already active, disable keyboard traversal
1563        and set it to mouse traversal */
1564 
1565     /* Was it the right button? */
1566     RC_MenuButton(w, event, &validButton);
1567 
1568     DEBUGOUT(_LtDebug("MENU", w, "%s:StartDrag(%d) - %s posted mine %s\n",
1569 	__FILE__, __LINE__,
1570 	RC_PopupPosted(XtParent(w)) ? XtName(RC_PopupPosted(XtParent(w))) : "None",
1571 	CBG_Submenu(w) ? XtName(CBG_Submenu(w)) : "None"
1572 	));
1573     if (validButton)
1574     {
1575 	if (CBG_Submenu(w) && RC_PopupPosted(XtParent(w)) == CBG_Submenu(w))
1576 	{
1577 	Cardinal i;
1578 
1579 	    for (i = 0; i < MGR_NumChildren(CBG_Submenu(w)); i++)
1580 	    {
1581 		_XmMenuDisarmItem(MGR_Children(CBG_Submenu(w))[i]);
1582 	    }
1583 	}
1584 	else
1585 	{
1586 	    RC_MenuShellPopdown(w, event, &poppedUp);
1587 	    _XmCascadingPopup(w, event, True);
1588 	    {
1589 	    Cardinal i;
1590 	    Widget menu = XtParent(w);
1591 
1592 		for (i = 0; i < MGR_NumChildren(menu); i++)
1593 		{
1594 		    _XmMenuDisarmItem(MGR_Children(menu)[i]);
1595 		}
1596 	    }
1597 	    XmCascadeButtonGadgetHighlight(w, True);
1598 	}
1599 
1600 	_XmSetInDragMode(w, True);
1601     }
1602 }
1603 
1604 static void
CascadePopupHandler(XtPointer clientData,XtIntervalId * id)1605 CascadePopupHandler(XtPointer clientData, XtIntervalId *id)
1606 {
1607     Widget w = (Widget)clientData;
1608 
1609     CBG_Timer(w) = 0;
1610 
1611     DEBUGOUT(_LtDebug(__FILE__, w, "CascadePopupHandler()\n"));
1612 
1613     _XmCascadingPopup(w, NULL, True);	/* FIX ME: NULL? */
1614 }
1615 
1616 
1617 static void
DelayedArm(Widget w,XEvent * event,String * params,Cardinal * num_params)1618 DelayedArm(Widget w, XEvent *event, String *params, Cardinal *num_params)
1619 {
1620     DEBUGOUT(_LtDebug(__FILE__, w, "DelayedArm()\n"));
1621 
1622     XAllowEvents(XtDisplay(w), SyncPointer, CurrentTime);
1623 
1624     if (_XmGetInDragMode(w))
1625     {
1626 	if (RC_PopupPosted(XtParent(w)) != CBG_Submenu(w))
1627 	{
1628 	Boolean poppedUp;
1629 
1630 	    RC_MenuShellPopdown(w, NULL, &poppedUp);
1631 	}
1632 	if (!RC_PopupPosted(XtParent(w)))
1633 	{
1634 	    CBG_Timer(w) = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
1635 					   CBG_MapDelay(w),
1636 					   CascadePopupHandler,
1637 					   (XtPointer)w);
1638 
1639 	    XmCascadeButtonGadgetHighlight(w, True);
1640 	}
1641     }
1642 }
1643 
1644 static void
CheckDisarm(Widget w,XEvent * event,String * params,Cardinal * num_params)1645 CheckDisarm(Widget w, XEvent *event, String *params, Cardinal *num_params)
1646 {
1647     int x = ((XLeaveWindowEvent *)event)->x_root;
1648     int y = ((XLeaveWindowEvent *)event)->y_root;
1649     Widget subpane;
1650 
1651     DEBUGOUT(_LtDebug(__FILE__, w, "CheckDisarm() - %i %i %i\n", x, y, XtHeight(w)));
1652 
1653     XAllowEvents(XtDisplay(w), SyncPointer, CurrentTime);
1654 
1655     if (_XmGetInDragMode(w))
1656     {
1657 	if (CBG_Timer(w))
1658 	{
1659 	    XtRemoveTimeOut(CBG_Timer(w));
1660 	    CBG_Timer(w) = 0;
1661 	}
1662 	if (!RC_PopupPosted(XtParent(w)) || (CBG_Submenu(w) != RC_PopupPosted(XtParent(w))))
1663 	{
1664 	    XmCascadeButtonGadgetHighlight(w, False);
1665 	}
1666 	else
1667 	{
1668 	    subpane = XtParent(CBG_Submenu(w));
1669 
1670 	    if (x < XtX(subpane) || x >= XtX(subpane) + XtWidth(subpane) ||
1671 		y < XtY(subpane) || y >= XtY(subpane) + XtHeight(subpane))
1672 	    {
1673 		Boolean poppedUp;
1674 
1675 		RC_MenuShellPopdown(w, event, &poppedUp);
1676 		XmCascadeButtonGadgetHighlight(w, False);
1677 	    }
1678 	}
1679     }
1680 }
1681 
1682 
1683 static void
Help(Widget w,XEvent * event,String * params,Cardinal * num_params)1684 Help(Widget w, XEvent *event, String *params, Cardinal *num_params)
1685 {
1686     Widget cur = w;
1687     XmAnyCallbackStruct cbs;
1688 
1689     cbs.reason = XmCR_HELP;
1690     cbs.event = event;
1691 
1692     while (cur != NULL)
1693     {
1694 	if (XtHasCallbacks(w, XmNhelpCallback) == XtCallbackHasSome)
1695 	{
1696 	    XtCallCallbacks(w, XmNhelpCallback, (XtPointer)&cbs);
1697 	    return;
1698 	}
1699 
1700 	cur = XtParent(cur);
1701     }
1702 }
1703 
1704 static void
ArmAndActivate(Widget w,XEvent * event,String * params,Cardinal * num_params)1705 ArmAndActivate(Widget w, XEvent *event, String *params, Cardinal *num_params)
1706 {
1707     DEBUGOUT(_LtDebug(__FILE__, w, "ArmAndActivate\n"));
1708 
1709     MGR_ActiveChild(XtParent(w)) = w;
1710     if (LabG_MenuType(w) == XmMENU_BAR)
1711     {
1712 	if (!RC_IsArmed(XtParent(w)))
1713 	{
1714 	    RCClass_MenuProcs(XtClass(XtParent(w)))(XmMENU_ARM, XtParent(w), NULL);
1715 	    _XmMenuFocus(XtParent(w), XmMENU_FOCUS_SAVE, CurrentTime);
1716 	    _XmSetInDragMode(XtParent(w), False);
1717 	}
1718 	_XmMenuFocus(XtParent(w), XmMENU_FOCUS_SET, CurrentTime);
1719 	MenuBarSelect(w, event, params, num_params);
1720 	DoSelect(w, event, params, num_params);
1721     }
1722     else if (LabG_MenuType(w) == XmMENU_OPTION)
1723     {
1724 	XmProcessTraversal(w, XmTRAVERSE_CURRENT);
1725 
1726 	if (CBG_Submenu(w) && !RC_IsArmed(CBG_Submenu(w)))
1727 	{
1728 	    DEBUGOUT(_LtDebug(__FILE__, w, "MENU_ARM\n"));
1729 
1730 	    RCClass_MenuProcs(XtClass(XtParent(w)))(XmMENU_ARM,
1731 						    XtParent(w), NULL);
1732 	}
1733 
1734 	CascadePopupHandler((XtPointer)w, NULL);
1735     }
1736     else /* pullright */
1737     {
1738 	CascadePopupHandler((XtPointer)w, NULL);
1739     }
1740 }
1741 
1742 static void
input_dispatch(Widget gadget,XEvent * event,Mask event_mask)1743 input_dispatch(Widget gadget, XEvent *event, Mask event_mask)
1744 {
1745     Cardinal num_params = 0;
1746 
1747     switch (event_mask)
1748     {
1749     case XmARM_EVENT:
1750 	if (LabG_MenuType(gadget) == XmMENU_BAR)
1751 	{
1752 	    MenuBarSelect(gadget, event, NULL, &num_params);
1753 	}
1754 	else if (LabG_MenuType(gadget) == XmMENU_OPTION)
1755 	{
1756 	    ArmAndPost(gadget, event, NULL, &num_params);
1757 	}
1758 	else
1759 	{
1760 	    StartDrag(gadget, event, NULL, &num_params);
1761 	}
1762 	break;
1763 
1764     case XmACTIVATE_EVENT:
1765 	DoSelect(gadget, event, NULL, &num_params);
1766 	break;
1767 
1768     case XmENTER_EVENT:
1769 	if ((LabG_MenuType(gadget) == XmMENU_PULLDOWN) ||
1770 	    (LabG_MenuType(gadget) == XmMENU_POPUP))	/* rws 23 Mar 1997 */
1771 	{
1772 	    DelayedArm(gadget, event, NULL, &num_params);
1773 	}
1774 	else if (LabG_MenuType(gadget) == XmMENU_BAR)
1775 	{
1776 	    MenuBarEnter(gadget, event, NULL, &num_params);
1777 	}
1778 	break;
1779 
1780     case XmLEAVE_EVENT:
1781 	if ((LabG_MenuType(gadget) == XmMENU_PULLDOWN) ||
1782 	    (LabG_MenuType(gadget) == XmMENU_POPUP))	/* rws 23 Mar 1997 */
1783 	{
1784 	    CheckDisarm(gadget, event, NULL, &num_params);
1785 	}
1786 	else if (LabG_MenuType(gadget) == XmMENU_BAR)
1787 	{
1788 	    MenuBarLeave(gadget, event, NULL, &num_params);
1789 	}
1790 	break;
1791 
1792     case XmFOCUS_IN_EVENT:
1793 	_XmFocusInGadget(gadget, event, NULL, &num_params);
1794 	break;
1795 
1796     case XmFOCUS_OUT_EVENT:
1797 	_XmFocusOutGadget(gadget, event, NULL, &num_params);
1798 	break;
1799 
1800     case XmBDRAG_EVENT:	/* FIX ME: MLM - is this right? */
1801 	_XmProcessDrag(gadget, event, NULL, NULL);
1802 	break;
1803 
1804     case XmHELP_EVENT:
1805 	Help(gadget, event, NULL, &num_params);
1806 	break;
1807     }
1808 }
1809 
1810 static Boolean
visual_change(Widget w,Widget parent,Widget n)1811 visual_change(Widget w,
1812 	      Widget parent,
1813 	      Widget n)
1814 {
1815     _XmWarning(w,"%s(%d) - visual_change not written\n", __FILE__, __LINE__);
1816     return False;
1817 }
1818 
1819 static void
MenuProcEntry(int proc,Widget w,...)1820 MenuProcEntry(int proc, Widget w,...)
1821 {
1822     va_list arg_list;
1823     /*
1824     XEvent *event = NULL;
1825     */
1826 
1827     va_start(arg_list, w);
1828 
1829     switch (proc)
1830     {
1831     case XmMENU_ARM:
1832 	{
1833 	/* XtExposeProc exp = XtClass(w)->core_class.expose; */
1834 
1835 	    XmCascadeButtonGadgetHighlight(w, True);
1836 	    XmProcessTraversal(w, XmTRAVERSE_CURRENT);
1837 	    MGR_ActiveChild(XtParent(w)) = w;
1838 	    /*
1839 	    (exp) (w, event, (Region)NULL);
1840 	    */
1841 	}
1842 	break;
1843     case XmMENU_DISARM:
1844 	{
1845 	/* XtExposeProc exp = XtClass(w)->core_class.expose; */
1846 
1847 	    XmCascadeButtonGadgetHighlight(w, False);
1848 	    MGR_ActiveChild(XtParent(w)) = NULL;
1849 	    /*
1850 	    (exp) (w, event, (Region)NULL);
1851 	    */
1852 	}
1853 	break;
1854     default:
1855 	_XmWarning(w, "%s(%d) - Invalid menuProc function", __FILE__, __LINE__);
1856 	break;
1857     }
1858 
1859     va_end(arg_list);
1860 }
1861 
1862 void
XmCascadeButtonGadgetHighlight(Widget w,Boolean highlight)1863 XmCascadeButtonGadgetHighlight(Widget w, Boolean highlight)
1864 {
1865     DEBUGOUT(_LtDebug(__FILE__, w,
1866 		      "XmCascadeButtonGadgetHighlight(hl %d, armed %d,"
1867 		      " apm 0x%X, cpm 0x%X), %s, geo %d %d %dx%d\n",
1868 		      highlight,
1869 		      XmIsPrimitive(w) ? CB_IsArmed(w) : CBG_IsArmed(w),
1870 		  XmIsPrimitive(w) ? CB_ArmedPixmap(w) : CBG_ArmedPixmap(w),
1871 	      XmIsPrimitive(w) ? CB_CascadePixmap(w) : CBG_CascadePixmap(w),
1872 		      _LtDebugMenuType2String(LabG_MenuType(w)),
1873 		      XtX(w), XtY(w), XtWidth(w), XtHeight(w)
1874 	     ));
1875 
1876     if (XmIsPrimitive(w))
1877     {
1878 	XmCascadeButtonHighlight(w, highlight);
1879 
1880 	return;
1881     }
1882     else if (!XmIsCascadeButtonGadget(w))
1883     {
1884 	_XmError(w,
1885 	    "XmCascadeButtonGadgetHighlight called with non-cascade button gadget");
1886 
1887 	return;
1888     }
1889 
1890     if (LabG_MenuType(w) != XmMENU_OPTION)
1891 	CBG_SetArmed(w, highlight);
1892 
1893     if (XtIsRealized(w))
1894     {
1895 	if (!highlight)
1896 	{
1897 	    _XmClearBorder(XtDisplayOfObject(w),
1898 			   XtWindowOfObject(w),
1899 			   XtX(w), XtY(w), XtWidth(w), XtHeight(w),
1900 			   LabG_Shadow(w));
1901 	}
1902 	draw_cascade(w);
1903     }
1904 }
1905 
1906 Widget
XmCreateCascadeButtonGadget(Widget parent,char * name,Arg * arglist,Cardinal argcount)1907 XmCreateCascadeButtonGadget(Widget parent, char *name,
1908 			    Arg *arglist, Cardinal argcount)
1909 {
1910     return XtCreateWidget(name,
1911 			  xmCascadeButtonGadgetClass,
1912 			  parent,
1913 			  arglist,
1914 			  argcount);
1915 }
1916