1 /*************************************<+>*************************************
2  *****************************************************************************
3  **
4  **   File:        MenuBtn.c
5  **
6  **   Project:     X Widgets
7  **
8  **   Description: Contains code for primitive widget class: MenuButton
9  **
10  *****************************************************************************
11  **
12  **   Copyright (c) 1988 by Hewlett-Packard Company
13  **   Copyright (c) 1988 by the Massachusetts Institute of Technology
14  **
15  **   Permission to use, copy, modify, and distribute this software
16  **   and its documentation for any purpose and without fee is hereby
17  **   granted, provided that the above copyright notice appear in all
18  **   copies and that both that copyright notice and this permission
19  **   notice appear in supporting documentation, and that the names of
20  **   Hewlett-Packard or  M.I.T.  not be used in advertising or publicity
21  **   pertaining to distribution of the software without specific, written
22  **   prior permission.
23  **
24  *****************************************************************************
25  *************************************<+>*************************************/
26 
27 /*
28  *#define DEBUG TRUE
29  */
30 #undef NLS16
31 
32 /*
33  * Include files & Static Routine Definitions
34  */
35 #include <string.h>
36 #include <X11/IntrinsicP.h>
37 #include <X11/StringDefs.h>
38 #include <X11/keysymdef.h>
39 #include <X11/Xatom.h>
40 #include <X11/Shell.h>
41 #include <Xw/Xw.h>
42 #include <Xw/XwP.h>
43 #include <Xw/MenuBtnP.h>
44 #include <Xw/MenuBtn.h>
45 
46 #ifdef NLS16
47 #include <X11/XHPlib.h>
48 #endif
49 
50 #ifndef XtRWidget
51 #define XtRWidget XtRPointer
52 #endif
53 
54 static void Redisplay();
55 static Boolean SetValues();
56 static void ClassPartInitialize();
57 static void Inverted();
58 static void NonInverted();
59 static void Select();
60 static void Enter();
61 static void Leave();
62 static void Moved();
63 static void Initialize();
64 static void Destroy();
65 static void Realize();
66 static void Resize();
67 static void IdealWidth();
68 static void Unhighlight();
69 static void Highlight();
70 static void SetCascadeEnabled();
71 static void ClearCascadeEnabled();
72 static void EnterParentsWindow();
73 static void SetTraversalType();
74 static void TraverseLeft();
75 static void TraverseRight();
76 static void TraverseNext();
77 static void TraversePrev();
78 static void TraverseHome();
79 static void TraverseUp();
80 static void TraverseDown();
81 static void TraverseNextTop();
82 static void Unmap();
83 static void Visibility();
84 Boolean _XwUniqueEvent();
85 
86 /*************************************<->*************************************
87  *
88  *
89  *   Description:  default translation table for class: MenuButton
90  *   -----------
91  *
92  *   Matches events with string descriptors for internal routines.
93  *
94  *************************************<->***********************************/
95 
96 
97 static char defaultTranslations[] =
98     "<Btn1Down>:             select()\n\
99      <Visible>:              visibility()\n\
100      <Unmap>:                unmap()\n\
101      <EnterWindow>:          enter()\n\
102      <LeaveWindow>:          leave()\n\
103      <Motion>:	             moved()\n\
104      <Key>Select:            select()\n\
105      <Key>Left:              traverseLeft()\n\
106      <Key>Up:                traverseUp()\n\
107      <Key>Right:             traverseRight()\n\
108      <Key>Down:              traverseDown()\n\
109      <Key>Prior:             traversePrev()\n\
110      <Key>Next:              traverseNext()\n\
111      <Key>KP_Enter:          traverseNextTop()\n\
112      <Key>Home:              traverseHome()";
113 
114 
115 
116 /*************************************<->*************************************
117  *
118  *
119  *   Description:  action list for class: MenuButton
120  *   -----------
121  *
122  *   Matches string descriptors with internal routines.
123  *
124  *************************************<->***********************************/
125 
126 static XtActionsRec actionsList[] =
127 {
128   {"select", 	      (XtActionProc) Select},
129   {"visibility",      (XtActionProc) Visibility},
130   {"unmap", 	      (XtActionProc) Unmap},
131   {"enter", 	      (XtActionProc) Enter},
132   {"leave", 	      (XtActionProc) Leave},
133   {"moved", 	      (XtActionProc) Moved},
134   {"traverseLeft",    (XtActionProc) TraverseLeft },
135   {"traverseRight",   (XtActionProc) TraverseRight },
136   {"traverseNext",    (XtActionProc) TraverseNext },
137   {"traversePrev",    (XtActionProc) TraversePrev },
138   {"traverseHome",    (XtActionProc) TraverseHome },
139   {"traverseUp",      (XtActionProc) TraverseUp },
140   {"traverseDown",    (XtActionProc) TraverseDown },
141   {"traverseNextTop", (XtActionProc) TraverseNextTop },
142 };
143 
144 /*************************************<->*************************************
145  *
146  *
147  *   Description:  resource list for class: MenuButton
148  *   -----------
149  *
150  *   Provides default resource settings for instances of this class.
151  *   To get full set of default settings, examine resouce list of super
152  *   classes of this class.
153  *
154  *************************************<->***********************************/
155 
156 static XtResource resources[] =
157 {
158    {
159       XtNborderWidth, XtCBorderWidth,XtRDimension, sizeof(Dimension),
160       XtOffset(XwMenuButtonWidget, core.border_width),
161       XtRString, "0"
162    },
163 
164    {
165       XtNlabelType, XtCLabelType, XtRLabelType, sizeof(int),
166       XtOffset(XwMenuButtonWidget, menubutton.labelType),
167       XtRString, "string"
168    },
169 
170    {
171       XtNlabelImage, XtCLabelImage, XtRImage, sizeof(XImage *),
172       XtOffset(XwMenuButtonWidget, menubutton.labelImage),
173       XtRImage, NULL
174    },
175 
176    {
177       XtNrectColor, XtCRectColor, XtRPixel, sizeof(Pixel),
178       XtOffset(XwMenuButtonWidget, menubutton.rectColor),
179       XtRString, "white"
180    },
181 
182    {
183       XtNrectStipple, XtCRectStipple, XtRPixmap, sizeof(Pixmap),
184       XtOffset(XwMenuButtonWidget, menubutton.rectStipple),
185       XtRPixmap, NULL
186    },
187 
188    {
189       XtNcascadeImage, XtCCascadeImage, XtRImage, sizeof(XImage *),
190       XtOffset(XwMenuButtonWidget, menubutton.cascadeImage),
191       XtRImage, NULL
192    },
193 
194    {
195       XtNmarkImage, XtCMarkImage, XtRImage, sizeof(XImage *),
196       XtOffset(XwMenuButtonWidget, menubutton.markImage),
197       XtRImage, NULL
198    },
199 
200    {
201       XtNsetMark, XtCSetMark, XtRBoolean, sizeof(Boolean),
202       XtOffset(XwMenuButtonWidget, menubutton.setMark),
203       XtRString, "FALSE"
204    },
205 
206    {
207       XtNnoPad, XtCNoPad, XtRBoolean, sizeof(Boolean),
208       XtOffset(XwMenuButtonWidget, menubutton.noPad),
209       XtRString, "FALSE"
210    },
211 
212    {
213       XtNcascadeOn, XtCCascadeOn, XtRWidget, sizeof(Widget),
214       XtOffset(XwMenuButtonWidget, menubutton.cascadeOn),
215       XtRWidget, NULL
216    },
217 
218    {
219       XtNkbdAccelerator, XtCKbdAccelerator, XtRString, sizeof(caddr_t),
220       XtOffset(XwMenuButtonWidget, menubutton.accelerator),
221       XtRString, NULL
222    },
223 
224    {
225       XtNhint, XtCHint, XtRString, sizeof(caddr_t),
226       XtOffset(XwMenuButtonWidget, menubutton.hint),
227       XtRString, NULL
228    },
229 
230    {
231       XtNhintProc, XtCHintProc, XtRFunction, sizeof(XwStrProc),
232       XtOffset(XwMenuButtonWidget, menubutton.hintProc),
233       XtRFunction, NULL
234    },
235 
236    {
237       XtNmgrOverrideMnemonic, XtCMgrOverrideMnemonic, XtRBoolean,
238       sizeof(Boolean),
239       XtOffset(XwMenuButtonWidget, menubutton.mgrOverrideMnemonic),
240       XtRString, "FALSE"
241    },
242 
243    {
244       XtNmnemonic, XtCMnemonic, XtRString, sizeof(caddr_t),
245       XtOffset(XwMenuButtonWidget, menubutton.mnemonic),
246       XtRString, NULL
247    },
248 
249    {
250       XtNhighlightStyle, XtCHighlightStyle, XtRHighlightStyle, sizeof (int),
251       XtOffset (XwPrimitiveWidget, primitive.highlight_style),
252       XtRString, "widget_defined"
253    },
254 
255    {
256       XtNcascadeSelect, XtCCallback, XtRCallback, sizeof(caddr_t),
257       XtOffset (XwMenuButtonWidget, menubutton.cascadeSelect),
258       XtRPointer, (caddr_t) NULL
259    },
260 
261    {
262       XtNcascadeUnselect, XtCCallback, XtRCallback, sizeof(caddr_t),
263       XtOffset (XwMenuButtonWidget, menubutton.cascadeUnselect),
264       XtRPointer, (caddr_t) NULL
265    },
266 
267    {
268       XtNmenuMgrId, XtCMenuMgrId, XtRWidget, sizeof(Widget),
269       XtOffset (XwMenuButtonWidget, menubutton.menuMgr),
270       XtRWidget, NULL
271    },
272 };
273 
274 /*************************************<->*************************************
275  *
276  *
277  *   Description:  global class record for instances of class: MenuButton
278  *   -----------
279  *
280  *   Defines default field settings for this class record.
281  *
282  *************************************<->***********************************/
283 
284 XwMenuButtonClassRec XwmenubuttonClassRec =
285 {
286   {
287 /* core_class fields */
288     /* superclass	  */	(WidgetClass) &XwbuttonClassRec,
289     /* class_name	  */	"XwMenuButton",
290     /* widget_size	  */	sizeof(XwMenuButtonRec),
291     /* class_initialize   */    NULL,
292     /* class_part_init    */    ClassPartInitialize,
293     /* class_inited       */	FALSE,
294     /* initialize	  */	Initialize,
295     /* initialize_hook    */	NULL,
296     /* realize		  */	Realize,
297     /* actions		  */	actionsList,
298     /* num_actions	  */	XtNumber(actionsList),
299     /* resources	  */	resources,
300     /* num_resources	  */	XtNumber(resources),
301     /* xrm_class	  */	NULLQUARK,
302     /* compress_motion	  */	TRUE,
303     /* compress_exposure  */	TRUE,
304     /* compress_enterlv   */	TRUE,    /* FIX ME LATER */
305     /* visible_interest	  */	FALSE,
306     /* destroy		  */	Destroy,
307     /* resize		  */	Resize,
308     /* expose		  */	Redisplay,
309     /* set_values	  */	SetValues,
310     /* set_values_hook    */	NULL,
311     /* set_values_almost  */	XtInheritSetValuesAlmost,
312     /* get_values_hook    */	NULL,
313     /* accept_focus	  */	NULL,
314     /* version     	  */	XtVersion,
315     /* cb List     	  */	NULL,
316     /* tm_table    	  */	defaultTranslations,
317     /* query_geometry     */	NULL,     /* FIX ME LATER */
318     /* display_accelerator	*/	XtInheritDisplayAccelerator,
319     /* extension		*/	NULL
320   },
321   {
322      /* primitive class fields */
323      /* border_highlight   */	Inverted,
324      /* border_unhighlight */	NonInverted,
325      /* select_proc        */	Select,
326      /* release_proc       */	NULL,
327      /* toggle_proc        */	NULL,
328      /* translations       */	NULL,
329   },
330   {
331      /* button class fields */	0,
332   },
333   {
334      /* menubutton class fields */
335      /* ideal width proc  */	IdealWidth,
336      /* unhighlight proc  */    Unhighlight,
337      /* highlight proc    */    Highlight,
338      /* cascade selected  */    SetCascadeEnabled,
339      /* cascade unselected*/    ClearCascadeEnabled,
340      /* enter parents win */    EnterParentsWindow,
341      /* cascadeSelectProc */	NULL,
342      /* cascadeUnselectProc */  NULL,
343      /* setTraversalType    */  SetTraversalType
344   }
345 };
346 WidgetClass XwmenubuttonWidgetClass = (WidgetClass)&XwmenubuttonClassRec;
347 WidgetClass XwmenuButtonWidgetClass = (WidgetClass)&XwmenubuttonClassRec;
348 
349 
350 /*************************************<->*************************************
351  *
352  *   SetCascadeEnabled (mbutton)
353  *
354  *   Description:
355  *   -----------
356  *   This routine is called by the Menu Manager to force the menubutton into
357  *   thinking that the cascade select callbacks have been recently called.
358  *
359  *   Inputs:
360  *   ------
361  *   mbutton = this menubutton widget
362  *
363  *   Outputs:
364  *   -------
365  *
366  *   Procedures Called
367  *   -----------------
368  *
369  *************************************<->***********************************/
SetCascadeEnabled(mbutton)370 static void SetCascadeEnabled (mbutton)
371 XwMenuButtonWidget mbutton;
372 {
373    mbutton->menubutton.cascadeEnabled = TRUE;
374 }
375 
376 /*************************************<->*************************************
377  *
378  *   ClearCascadeEnabled (mbutton)
379  *
380  *   Description:
381  *   -----------
382  *   This routine is called by the Menu Manager to force the menubutton into
383  *   thinking that the cascade unselect callbacks have been recently called.
384  *
385  *   Inputs:
386  *   ------
387  *   mbutton = this menubutton widget
388  *
389  *   Outputs:
390  *   -------
391  *
392  *   Procedures Called
393  *   -----------------
394  *
395  *************************************<->***********************************/
ClearCascadeEnabled(mbutton)396 static void ClearCascadeEnabled (mbutton)
397 XwMenuButtonWidget mbutton;
398 {
399    mbutton->menubutton.cascadeEnabled = FALSE;
400 }
401 
402 /*************************************<->*************************************
403  *
404  *  ClassPartInitialize (parameters)
405  *
406  *   Description:
407  *   -----------
408  *
409  *
410  *   Inputs:
411  *   ------
412  *
413  *   Outputs:
414  *   -------
415  *
416  *   Procedures Called
417  *   -----------------
418  *
419  *************************************<->***********************************/
420 
ClassPartInitialize(wc)421 static void ClassPartInitialize (wc)
422 
423    register XwMenuButtonWidgetClass wc;
424 
425 {
426    register XwMenuButtonWidgetClass super =
427             (XwMenuButtonWidgetClass) wc->core_class.superclass;
428 
429    if (wc->menubutton_class.idealWidthProc == XtInheritIdealWidthProc)
430       wc->menubutton_class.idealWidthProc =
431             super->menubutton_class.idealWidthProc;
432 
433    if (wc->menubutton_class.unhighlightProc == XtInheritUnhighlightProc)
434       wc->menubutton_class.unhighlightProc =
435             super->menubutton_class.unhighlightProc;
436 
437    if (wc->menubutton_class.highlightProc == XtInheritHighlightProc)
438       wc->menubutton_class.highlightProc =
439             super->menubutton_class.highlightProc;
440 
441    if (wc->menubutton_class.setCascadeProc == XtInheritSetCascadeProc)
442       wc->menubutton_class.setCascadeProc =
443             super->menubutton_class.setCascadeProc;
444 
445    if (wc->menubutton_class.clearCascadeProc == XtInheritClearCascadeProc)
446       wc->menubutton_class.clearCascadeProc =
447             super->menubutton_class.clearCascadeProc;
448 
449    if (wc->menubutton_class.enterParentProc == XtInheritEnterParentProc)
450       wc->menubutton_class.enterParentProc =
451             super->menubutton_class.enterParentProc;
452 
453    if (wc->menubutton_class.cascadeSelectProc == XtInheritCascadeSelectProc)
454       wc->menubutton_class.cascadeSelectProc =
455             super->menubutton_class.cascadeSelectProc;
456 
457    if (wc->menubutton_class.cascadeUnselectProc == XtInheritCascadeUnselectProc)
458       wc->menubutton_class.cascadeUnselectProc =
459             super->menubutton_class.cascadeUnselectProc;
460 
461    if (wc->menubutton_class.setTraversalType == XtInheritSetTraversalTypeProc)
462       wc->menubutton_class.setTraversalType =
463             super->menubutton_class.setTraversalType;
464 }
465 
466 
467 /*************************************<->*************************************
468  *
469  *   ComputeHeight (mbutton)
470  *
471  *   Description:
472  *   -----------
473  *   Returns the ideal height of the menubutton by considering whether the
474  *   label is text or image.
475  *
476  *   Inputs:
477  *   ------
478  *   mbutton = widget to compute height of
479  *
480  *   Outputs:
481  *   -------
482  *   returns the ideal height of mbutton
483  *
484  *   Procedures Called
485  *   -----------------
486  *
487  *************************************<->***********************************/
488 
ComputeHeight(mbutton)489 static Dimension ComputeHeight(mbutton)
490 XwMenuButtonWidget mbutton;
491 {
492    Dimension max = 0;
493 
494    if (mbutton->menubutton.labelType == XwSTRING)
495       max = mbutton->button.label_height;
496 
497    if ((mbutton->menubutton.labelType == XwIMAGE) &&
498        (mbutton->menubutton.labelImage->height > max))
499       max = mbutton->menubutton.labelImage->height;
500 
501    if (mbutton->menubutton.markImage->height > max)
502       max = mbutton->menubutton.markImage->height;
503 
504    if (mbutton->menubutton.cascadeImage->height > max)
505       max = mbutton->menubutton.cascadeImage->height;
506 
507    return (max + 2 * mbutton->button.internal_height +
508 	   2 * mbutton->primitive.highlight_thickness);
509 
510 }
511 
512 /*************************************<->*************************************
513  *
514  *   ComputeVertical
515  *
516  *   Description:
517  *   -----------
518  *   Computes the values for mark_y, label_y and cascade_y.
519  *
520  *   Inputs:
521  *   ------
522  *   mbutton = menubutton to compute and set values for
523  *
524  *   Outputs:
525  *   -------
526  *
527  *   Procedures Called
528  *   -----------------
529  *
530  *************************************<->***********************************/
531 
ComputeVertical(mbutton)532 static void ComputeVertical (mbutton)
533 XwMenuButtonWidget mbutton;
534 {
535    Dimension string_y;
536 
537    string_y = (mbutton->core.height - mbutton->button.label_height)/2 +
538                mbutton->button.font->max_bounds.ascent;
539 
540    if (mbutton->menubutton.labelType == XwSTRING)
541       mbutton->button.label_y = string_y;
542 
543    else if (mbutton->menubutton.labelImage)
544       mbutton->button.label_y = (mbutton->core.height -
545 		 		   mbutton->menubutton.labelImage->height) / 2;
546 
547    mbutton->menubutton.mark_y = (mbutton->core.height -
548 				 mbutton->menubutton.markImage->height)/2;
549 
550    mbutton->menubutton.cascade_y = (mbutton->core.height -
551 				   mbutton->menubutton.cascadeImage->height)/2;
552 
553 }
554 
555 /*************************************<->*************************************
556  *
557  *   SetUnderline (mbutton)
558  *
559  *   Description:
560  *   -----------
561  *   Set the underline parameters underline_width and underline_y.
562  *
563  *   Inputs:
564  *   ------
565  *   mbutton = menubutton
566  *
567  *   Outputs:
568  *   -------
569  *
570  *   Procedures Called
571  *   -----------------
572  *   XTextWidth ()
573  *   XGetFontProperty ()
574  *
575  *************************************<->***********************************/
576 
SetUnderline(mbutton)577 static void SetUnderline (mbutton)
578 XwMenuButtonWidget mbutton;
579 {
580    int i, temp;
581 
582    if ((!mbutton->menubutton.mgrOverrideMnemonic) &&
583        (mbutton->menubutton.mnemonic))
584    {
585       mbutton->menubutton.mnemonicMatch = FALSE;
586       temp = XwStrlen (mbutton->button.label);
587 
588       for (i = 0; i < temp;)
589       {
590 #ifdef NLS16
591         if (XHPIs16bitCharacter (mbutton->button.font->fid,
592                                  mbutton->button.label[i],
593                                  mbutton->button.label[i+1]) == NULL)
594         {
595 #endif
596            if (*mbutton->menubutton.mnemonic ==
597                (char) mbutton->button.label[i])
598            {
599 	      unsigned long bval;
600 
601               mbutton->menubutton.mnemonicMatch = TRUE;
602               mbutton->menubutton.underline_width =
603   	         XTextWidth(mbutton->button.font, mbutton->button.label+i, 1);
604 
605               mbutton->menubutton.underline_x =
606   	         XTextWidth(mbutton->button.font, mbutton->button.label, i) +
607 	         mbutton->primitive.highlight_thickness +
608                  4 * mbutton->button.internal_width + XwMARKWIDTH;
609 
610 	      if (XGetFontProperty(mbutton->button.font, XA_UNDERLINE_POSITION,
611 			           &bval) == 0)
612 	         mbutton->menubutton.underline_y =
613                                     mbutton->button.font->descent +1;
614 	      else
615 	         mbutton->menubutton.underline_y = (Dimension) bval;
616 
617               mbutton->menubutton.underline_y += mbutton->button.label_y;
618               break;
619             }
620             else
621                i += 1;
622 #ifdef NLS16
623          }
624          else
625             i += 2;
626 #endif
627       }
628    }
629    else
630       mbutton->menubutton.mnemonicMatch = FALSE;
631 }
632 
633 /*************************************<->*************************************
634  *
635  *   GetGC (mbutton)
636  *
637  *   Description:
638  *   -----------
639  *   Creates image_GC
640  *
641  *   Inputs:
642  *   ------
643  *   mbutton = menubutton
644  *
645  *   Outputs:
646  *   -------
647  *
648  *   Procedures Called
649  *   -----------------
650  *   XtGetGC()
651  *
652  *************************************<->***********************************/
653 
GetGC(mbutton)654 static void GetGC (mbutton)
655 XwMenuButtonWidget mbutton;
656 {
657 
658    XGCValues values;
659    unsigned long dostipple = 0;
660 
661    values.function = GXcopy;
662    values.plane_mask = AllPlanes;
663    values.subwindow_mode = ClipByChildren;
664    values.clip_x_origin = 0;
665    values.clip_y_origin = 0;
666    values.clip_mask = None;
667    values.fill_style = FillSolid;
668    values.graphics_exposures = True;
669 
670    values.foreground = mbutton->primitive.foreground;
671    values.background = mbutton->core.background_pixel;
672 
673    mbutton->menubutton.defPixmap_GC =
674      XtGetGC ((Widget) mbutton,
675 	      GCFunction | GCPlaneMask | GCSubwindowMode |
676 	      GCGraphicsExposures | GCClipXOrigin | GCClipYOrigin |
677 	      GCClipMask | GCForeground | GCBackground,
678 	      &values);
679 
680    values.foreground = mbutton->core.background_pixel;
681    values.background = mbutton->primitive.foreground;
682 
683    mbutton->menubutton.invertPixmap_GC =
684      XtGetGC ((Widget) mbutton,
685 	      GCFunction | GCPlaneMask | GCSubwindowMode |
686 	      GCGraphicsExposures | GCClipXOrigin | GCClipYOrigin |
687 	      GCClipMask | GCForeground | GCBackground,
688 	      &values);
689 
690    values.background = mbutton->core.background_pixel;
691    values.stipple = mbutton->menubutton.rectStipple;
692    if (values.stipple != (Pixmap)NULL) {
693       dostipple = GCStipple;
694       values.fill_style = FillOpaqueStippled;
695       values.foreground = mbutton->primitive.foreground;
696    }
697    else
698       values.foreground = mbutton->menubutton.rectColor;
699 
700    mbutton->menubutton.rect_GC =
701      XtGetGC ((Widget) mbutton,
702               GCFunction | GCPlaneMask | GCSubwindowMode |
703               GCGraphicsExposures | GCClipXOrigin | GCClipYOrigin |
704               GCClipMask | GCForeground | GCBackground | dostipple |
705 	      GCFillStyle, &values);
706 }
707 
708 /*************************************<->*************************************
709  *
710  *   GetDefImages
711  *
712  *   Description:
713  *   -----------
714  *
715  *   Inputs:
716  *   ------
717  *   mbutton = menubutton
718  *
719  *   Outputs:
720  *   -------
721  *
722  *   Procedures Called
723  *   -----------------
724  *
725  *************************************<->***********************************/
726 
GetDefImages(mbutton)727 static void GetDefImages (mbutton)
728 XwMenuButtonWidget mbutton;
729 {
730   static unsigned char defMarkData[] =
731   {
732    0x00, 0x10, 0x00, 0x38, 0x00, 0x7c, 0x00, 0x3c,
733    0x00, 0x1e, 0x00, 0x0e, 0x00, 0x07, 0x00, 0x07,
734    0x8c, 0x03, 0x8e, 0x01, 0xde, 0x01, 0xdc, 0x00,
735    0xd8, 0x00, 0x70, 0x00, 0x70, 0x00, 0x20, 0x00,
736   };
737 
738   static unsigned char defCascadeData[] =
739   {
740    0x80, 0x00, 0x80, 0x01, 0x80, 0x03, 0x80, 0x07,
741    0x80, 0x0f, 0xfe, 0x1f, 0xfe, 0x3f, 0xfe, 0x7f,
742    0xfe, 0x3f, 0xfe, 0x1f, 0x80, 0x0f, 0x80, 0x07,
743    0x80, 0x03, 0x80, 0x01, 0x80, 0x00, 0x00, 0x00
744   };
745 
746   mbutton->menubutton.defMarkImage =
747      XCreateImage (XtDisplay(mbutton), CopyFromParent, 1, XYBitmap, 0,
748 		   defMarkData, 16, 16, 8, 2);
749 
750   mbutton->menubutton.defMarkImage->byte_order = MSBFirst;
751   mbutton->menubutton.defMarkImage->bitmap_bit_order = LSBFirst;
752   mbutton->menubutton.defMarkImage->bitmap_unit = 8;
753 
754 
755   mbutton->menubutton.defCascadeImage =
756      XCreateImage (XtDisplay(mbutton), CopyFromParent, 1, XYBitmap, 0,
757 		   defCascadeData, 16, 16, 8, 2);
758 
759   mbutton->menubutton.defCascadeImage->byte_order = MSBFirst;
760   mbutton->menubutton.defCascadeImage->bitmap_bit_order = LSBFirst;
761   mbutton->menubutton.defCascadeImage->bitmap_unit = 8;
762 }
763 
764 /*************************************<->*************************************
765  *
766  *   CreatePixmap
767  *
768  *   Description:
769  *   -----------
770  *
771  *   Inputs:
772  *   ------
773  *   mbutton = menubutton
774  *
775  *   Outputs:
776  *   -------
777  *
778  *   Procedures Called
779  *   -----------------
780  *
781  *************************************<->***********************************/
782 
CreatePixmap(mbutton,image,pix,invertedPix)783 static void CreatePixmap (mbutton, image, pix, invertedPix)
784 XwMenuButtonWidget  mbutton;
785 XImage            * image;
786 Pixmap            * pix;
787 Pixmap            * invertedPix;
788 {
789    if (*pix != (Pixmap)NULL)
790       XFreePixmap (XtDisplay(mbutton), *pix);
791 
792    if (*invertedPix != (Pixmap)NULL)
793       XFreePixmap (XtDisplay(mbutton), *invertedPix);
794 
795    if (image)
796    {
797       *pix = XCreatePixmap (XtDisplay(mbutton),
798 			    RootWindowOfScreen(XtScreen(mbutton)),
799 			    image->width, image->height,
800 			    DefaultDepthOfScreen(XtScreen(mbutton)));
801 
802       XPutImage (XtDisplay(mbutton), *pix, mbutton->menubutton.defPixmap_GC,
803 		 image, 0, 0, 0, 0, image->width, image->height);
804 
805       if (image->format == XYBitmap)
806       {
807 	 *invertedPix = XCreatePixmap (XtDisplay(mbutton),
808 				     RootWindowOfScreen(XtScreen(mbutton)),
809 				     image->width, image->height,
810 				     DefaultDepthOfScreen(XtScreen(mbutton)));
811 
812 	 XPutImage (XtDisplay(mbutton), *invertedPix,
813 		    mbutton->menubutton.invertPixmap_GC,
814 		    image, 0, 0, 0, 0, image->width, image->height);
815       }
816 
817    }
818    else
819    {
820       *pix = (Pixmap)NULL;
821       *invertedPix = (Pixmap)NULL;
822    }
823 }
824 
825 /*************************************<->*************************************
826  *
827  *   IdealWidth
828  *
829  *   Description:
830  *   -----------
831  *   NOTE!!! This should be eventually replaced by a QueryProc.
832  *
833  *   Inputs:
834  *   ------
835  *   w = menubutton widget
836  *
837  *
838  *   Outputs:
839  *   -------
840  *
841  *   Procedures Called
842  *   -----------------
843  *
844  *************************************<->***********************************/
845 
IdealWidth(w,width)846 static void IdealWidth (w, width)
847 Widget w;
848 Dimension * width;
849 {
850    XwMenuButtonWidget mbutton = (XwMenuButtonWidget) w;
851 
852    *width = 2 * mbutton->primitive.highlight_thickness +
853            2 * (XwMENUBTNPAD + mbutton->button.internal_width) +
854 	   XwMARKWIDTH + XwCASCADEWIDTH;
855 
856    if (mbutton->menubutton.labelType == XwSTRING)
857      *width  += mbutton->button.label_width;
858    else if (mbutton->menubutton.labelType == XwIMAGE)
859       *width += mbutton->menubutton.labelImage->width;
860 }
861 
862 /*************************************<->*************************************
863  *
864  *  Initialize (request, new)
865  *
866  *   Description:
867  *   -----------
868  *     This is the menubutton instance initialize procedure.
869  *
870  *
871  *   Inputs:
872  *   ------
873  *     request  = original instance record;
874  *
875  *     new      = instance record with modifications induced by
876  *                other initialize routines, changes are made to this
877  *                record;
878  *
879  *     args     = argument list specified in XtCreateWidget;
880  *
881  *     num_args = argument count;
882  *
883  *   Outputs:
884  *   -------
885  *
886  *   Procedures Called
887  *   -----------------
888  *
889  *************************************<->***********************************/
890 
Initialize(request,new)891 static void Initialize (request, new)
892  Widget request, new;
893 {
894    Dimension	dim;
895    KeySym tempKeysym;
896 
897    XwMenuButtonWidget mbutton = (XwMenuButtonWidget) new;
898 
899    /* Augment our translations to include the traversal actions */
900    XtAugmentTranslations ((Widget)mbutton,
901                      XwprimitiveClassRec.primitive_class.translations);
902 
903    /*
904     * Always disable traversal in a menubutton.  Since the traversal
905     * state is inherited from the menu manager, we will let it control
906     * our traversal state.
907     */
908    mbutton->primitive.traversal_type = XwHIGHLIGHT_OFF;
909 
910    mbutton->menubutton.cascadeEnabled = FALSE;
911    mbutton->menubutton.inverted = FALSE;
912    mbutton->menubutton.labelPixmap =
913       mbutton->menubutton.markPixmap =
914 	 mbutton->menubutton.cascadePixmap =
915 	    mbutton->menubutton.invertLabelPixmap =
916 	       mbutton->menubutton.invertMarkPixmap =
917 		  mbutton->menubutton.invertCascadePixmap = (Pixmap)NULL;
918 
919    GetDefImages(mbutton);
920    GetGC(mbutton);
921 
922    /*
923     * If the menuMgr field has not been set up, check if in a menu system
924     * (menu manager as ancestor).
925     */
926    if (mbutton->menubutton.menuMgr == NULL)
927    {
928       if ((XtIsSubclass (XtParent (mbutton), XwmenupaneWidgetClass)) &&
929 	  (XtIsSubclass (XtParent (XtParent (mbutton)), shellWidgetClass)) &&
930 	  (XtIsSubclass (XtParent (XtParent (XtParent (mbutton))),
931 			 XwmenumgrWidgetClass)))
932       {
933 	 mbutton->menubutton.menuMgr =
934 	    (Widget) XtParent (XtParent (XtParent(mbutton)));
935       }
936    }
937 
938    /*
939     * We need to malloc space for the strings and copy them to our
940     * space.  The toolkit simply copies the pointer to the string.
941     */
942    if ((mbutton->menubutton.accelerator) &&
943        (_XwMapKeyEvent (mbutton->menubutton.accelerator,
944 			&mbutton->menubutton.accelEventType,
945 			&tempKeysym,
946 			&mbutton->menubutton.accelModifiers)))
947    {
948       mbutton->menubutton.accelDetail = XKeysymToKeycode (XtDisplay(mbutton),
949                                         tempKeysym);
950       mbutton->menubutton.accelerator =
951        strcpy(XtMalloc((unsigned)(XwStrlen(mbutton->menubutton.accelerator)+1)),
952 		mbutton->menubutton.accelerator);
953    }
954    else
955    {
956       if (mbutton->menubutton.accelerator)
957 	 XtWarning ("MenuButton: Invalid accelerator; disabling feature");
958       mbutton->menubutton.accelerator = NULL;
959       mbutton->menubutton.accelEventType = 0;
960       mbutton->menubutton.accelDetail = 0;
961       mbutton->menubutton.accelModifiers = 0;
962    }
963 
964    if (mbutton->menubutton.hint)
965       mbutton->menubutton.hint =
966        strcpy(XtMalloc((unsigned)(XwStrlen(mbutton->menubutton.hint)+1)),
967 		mbutton->menubutton.hint);
968 
969    /*
970     * malloc space for mnemonic.  Only take 1st character & null
971     */
972    if ((mbutton->menubutton.mnemonic) &&
973        (*(mbutton->menubutton.mnemonic) != '\0'))
974    {
975       char mne = mbutton->menubutton.mnemonic[0];
976 
977       mbutton->menubutton.mnemonic = (String) XtMalloc(2);
978       mbutton->menubutton.mnemonic[0] = mne;
979       mbutton->menubutton.mnemonic[1] = '\0';
980    }
981    else
982       if (mbutton->menubutton.mnemonic)
983 	 XtWarning ("MenuButton: Invalid mnemonic; disabling feature");
984 
985    if (mbutton->menubutton.labelImage)
986 	 CreatePixmap(mbutton, mbutton->menubutton.labelImage,
987 		      &mbutton->menubutton.labelPixmap,
988 		      &mbutton->menubutton.invertLabelPixmap);
989 
990    if (!mbutton->menubutton.markImage)
991      mbutton->menubutton.markImage = mbutton->menubutton.defMarkImage;
992 
993    CreatePixmap(mbutton, mbutton->menubutton.markImage,
994 		&mbutton->menubutton.markPixmap,
995 		&mbutton->menubutton.invertMarkPixmap);
996 
997    if (!mbutton->menubutton.cascadeImage)
998      mbutton->menubutton.cascadeImage = mbutton->menubutton.defCascadeImage;
999 
1000    CreatePixmap(mbutton, mbutton->menubutton.cascadeImage,
1001 		&mbutton->menubutton.cascadePixmap,
1002 		&mbutton->menubutton.invertCascadePixmap);
1003 
1004    if (request->core.height <= 0)
1005       mbutton->core.height = ComputeHeight(mbutton);
1006 
1007    ComputeVertical(mbutton);
1008    SetUnderline(mbutton);
1009 
1010    if (request->core.width <= 0)
1011       IdealWidth(mbutton, &mbutton->core.width);
1012 }
1013 
1014 /*************************************<->*************************************
1015  *
1016  *   Destroy
1017  *
1018  *   Description:
1019  *   -----------
1020  *
1021  *   Inputs:
1022  *   ------
1023  *
1024  *   Outputs:
1025  *   -------
1026  *
1027  *   Procedures Called
1028  *   -----------------
1029  *
1030  *************************************<->***********************************/
1031 
Destroy(mbutton)1032 static void Destroy (mbutton)
1033 XwMenuButtonWidget mbutton;
1034 {
1035    if (mbutton->menubutton.accelerator)
1036       XtFree (mbutton->menubutton.accelerator);
1037 
1038    XtDestroyGC (mbutton->menubutton.defPixmap_GC);
1039    XtDestroyGC (mbutton->menubutton.inverted_GC);
1040    XtDestroyGC (mbutton->menubutton.invertPixmap_GC);
1041    XtDestroyGC (mbutton->menubutton.rect_GC);
1042 
1043    mbutton->menubutton.defMarkImage->data = NULL;
1044    XDestroyImage (mbutton->menubutton.defMarkImage);
1045    mbutton->menubutton.defCascadeImage->data = NULL;
1046    XDestroyImage (mbutton->menubutton.defCascadeImage);
1047 
1048    XtRemoveAllCallbacks ((Widget)mbutton, XtNcascadeSelect);
1049    XtRemoveAllCallbacks ((Widget)mbutton, XtNcascadeUnselect);
1050 
1051    XFreePixmap (XtDisplay(mbutton), mbutton->menubutton.markPixmap);
1052    XFreePixmap (XtDisplay(mbutton), mbutton->menubutton.cascadePixmap);
1053    if (mbutton->menubutton.labelPixmap)
1054       XFreePixmap (XtDisplay(mbutton), mbutton->menubutton.labelPixmap);
1055 }
1056 
1057 /*************************************<->*************************************
1058  *
1059  *  Realize
1060  *
1061  *   Description:
1062  *   -----------
1063  *     Creates the window for this menubutton instance.  Sets bit gravity
1064  *     so that on resize the menubutton is repainted.
1065  *
1066  *
1067  *   Inputs:
1068  *   ------
1069  *     w  =  widget to be realized.
1070  *
1071  *     valueMask = contains event mask for this window/widget.
1072  *
1073  *     attributes = window attributes for this window/widget.
1074  *
1075  *   Outputs:
1076  *   -------
1077  *
1078  *   Procedures Called
1079  *   -----------------
1080  *   XtCreateWindow()
1081  *************************************<->***********************************/
1082 
Realize(w,p_valueMask,attributes)1083 static void Realize(w, p_valueMask, attributes)
1084 Widget w;
1085 XtValueMask * p_valueMask;
1086 XSetWindowAttributes * attributes;
1087 {
1088    XwMenuButtonWidget mbutton = (XwMenuButtonWidget) w;
1089 
1090    XtValueMask valueMask = *p_valueMask;
1091    valueMask |= CWBitGravity;
1092    attributes->bit_gravity = ForgetGravity;
1093 
1094 
1095    XtCreateWindow ((Widget)mbutton, InputOutput, (Visual *) CopyFromParent,
1096 		   valueMask, attributes);
1097 
1098    _XwRegisterName (mbutton);
1099 } /* Realize */
1100 
1101 /*************************************<->*************************************
1102  *
1103  *  Select (w, event)                  PRIVATE
1104  *
1105  *   Description:
1106  *   -----------
1107  *     Mark menubutton as selected, (i.e., draw it as active)
1108  *     Generate the correct callbacks.
1109  *
1110  *
1111  *   Inputs:
1112  *   ------
1113  *     w           =   widget instance that was selected.
1114  *     event       =   event record
1115  *
1116  *   Outputs:
1117  *   -------
1118  *
1119  *   Procedures Called
1120  *   -----------------
1121   *   XtCallCallbacks()
1122  *************************************<->***********************************/
1123 
Select(w,event)1124 static void Select(w,event)
1125 Widget w;
1126 XEvent *event;
1127 
1128 {
1129    XwMenuButtonWidget mbutton = (XwMenuButtonWidget) w;
1130 
1131    /*  Don't do anything if its not sensitive.  */
1132 
1133    if (XtIsSensitive((Widget)mbutton))
1134    {
1135      /*
1136       * if there is a menu manager, call the process select routine to
1137       * determine if the event is valid for the menu system.
1138       */
1139      if (mbutton->menubutton.menuMgr)
1140      {
1141 	if ((*(((XwMenuMgrWidgetClass) XtClass(mbutton->menubutton.menuMgr))->
1142 	       menu_mgr_class.processSelect))
1143 	    (mbutton->menubutton.menuMgr, mbutton, event) == FALSE)
1144 	{
1145 	   return;
1146 	}
1147      }
1148 
1149      XtCallCallbacks ((Widget)mbutton, XtNselect, NULL);
1150   }
1151 }
1152 
1153 /*************************************<->*************************************
1154  *
1155  *   DrawLabelMarkCascade (mbutton)
1156  *
1157  *   Description:
1158  *   -----------
1159  *
1160  *   Inputs:
1161  *   ------
1162  *
1163  *   Outputs:
1164  *   -------
1165  *
1166  *   Procedures Called
1167  *   -----------------
1168  *
1169  *************************************<->***********************************/
1170 
DrawLabelMarkCascade(mbutton)1171 static void DrawLabelMarkCascade (mbutton)
1172 XwMenuButtonWidget  mbutton;
1173 {
1174    Dimension labelStarts;
1175    GC theGC;
1176    Pixmap thePixmap;
1177 
1178    if (mbutton->menubutton.inverted)
1179       theGC = mbutton->button.inverse_GC;
1180    else
1181       theGC = mbutton->button.normal_GC;
1182 
1183 
1184    if (mbutton->menubutton.noPad == True)
1185       labelStarts = mbutton->primitive.highlight_thickness +
1186 		 mbutton->button.internal_width;
1187    else
1188       labelStarts = mbutton->primitive.highlight_thickness +
1189                  mbutton->button.internal_width + XwMENUBTNPAD + XwMARKWIDTH;
1190    /*
1191     * Draw the label with its underline if needed.
1192     */
1193    if (mbutton->menubutton.labelType == XwSTRING)
1194    {
1195       XDrawString(
1196 		  XtDisplay(mbutton), XtWindow(mbutton), theGC,
1197 		  labelStarts, mbutton->button.label_y,
1198 		  mbutton->button.label, (int) mbutton->button.label_len);
1199 
1200       if ((!mbutton->menubutton.mgrOverrideMnemonic) &&
1201           (mbutton->menubutton.mnemonicMatch))
1202 	 XDrawLine(
1203 		XtDisplay(mbutton), XtWindow(mbutton), theGC,
1204 		mbutton->menubutton.underline_x,
1205                 mbutton->menubutton.underline_y,
1206 		mbutton->menubutton.underline_x +
1207                   mbutton->menubutton.underline_width,
1208 		mbutton->menubutton.underline_y);
1209    }
1210    else if (mbutton->menubutton.labelType == XwRECT)
1211    {
1212       /* Draw a colored or stippled rectangle with a border around it */
1213 
1214       if (mbutton->menubutton.noPad == True) {
1215          XFillRectangle(
1216 		XtDisplay(mbutton), XtWindow(mbutton),
1217 		mbutton->menubutton.rect_GC,
1218 		2, 2, mbutton->menubutton.labelImage->width - 1,
1219 		mbutton->menubutton.labelImage->height - 1);
1220          XDrawRectangle(
1221 		XtDisplay(mbutton), XtWindow(mbutton), theGC,
1222 		2, 2, mbutton->menubutton.labelImage->width - 1,
1223 		mbutton->menubutton.labelImage->height - 1);
1224       }
1225       else {
1226          XFillRectangle(
1227 		XtDisplay(mbutton), XtWindow(mbutton),
1228 		mbutton->menubutton.rect_GC,
1229 		XwMARKWIDTH + 3, 3, mbutton->core.width - XwMARKWIDTH - 6,
1230 		mbutton->core.height - 6);
1231          XDrawRectangle(
1232 		XtDisplay(mbutton), XtWindow(mbutton), theGC,
1233 		XwMARKWIDTH + 3, 3, mbutton->core.width - XwMARKWIDTH - 6,
1234 		mbutton->core.height - 6);
1235       }
1236    }
1237    else
1238    {
1239       if ((mbutton->menubutton.inverted) &&
1240 	  (mbutton->menubutton.invertLabelPixmap))
1241 	 thePixmap = mbutton->menubutton.invertLabelPixmap;
1242       else
1243 	 thePixmap = mbutton->menubutton.labelPixmap;
1244 
1245       XCopyArea (XtDisplay(mbutton), thePixmap, XtWindow(mbutton),
1246 		 mbutton->menubutton.defPixmap_GC, 0, 0,
1247 		 mbutton->menubutton.labelImage->width,
1248 		 mbutton->menubutton.labelImage->height,
1249 		 labelStarts, mbutton->button.label_y);
1250    }
1251 
1252    /*
1253     * If the mark is set, display the mark.
1254     */
1255    if (mbutton->menubutton.setMark)
1256    {
1257       if ((mbutton->menubutton.inverted) &&
1258 	  (mbutton->menubutton.invertMarkPixmap))
1259 	 thePixmap = mbutton->menubutton.invertMarkPixmap;
1260       else
1261 	 thePixmap = mbutton->menubutton.markPixmap;
1262 
1263       XCopyArea (XtDisplay(mbutton), thePixmap, XtWindow(mbutton),
1264 		 mbutton->menubutton.defPixmap_GC, 0, 0,
1265 		 mbutton->menubutton.markImage->width,
1266 		 mbutton->menubutton.markImage->height,
1267 		 mbutton->button.internal_width +
1268 		         mbutton->primitive.highlight_thickness,
1269 		 mbutton->menubutton.mark_y);
1270    }
1271 
1272    /*
1273     * If the cascade is set, display it.
1274     */
1275    if (mbutton->menubutton.cascadeOn)
1276    {
1277       if ((mbutton->menubutton.inverted) &&
1278 	  (mbutton->menubutton.invertCascadePixmap))
1279 	 thePixmap = mbutton->menubutton.invertCascadePixmap;
1280       else
1281 	 thePixmap = mbutton->menubutton.cascadePixmap;
1282 
1283       XCopyArea (XtDisplay(mbutton), thePixmap, XtWindow(mbutton),
1284 		 mbutton->menubutton.defPixmap_GC, 0, 0,
1285 		 mbutton->menubutton.cascadeImage->width,
1286 		 mbutton->menubutton.cascadeImage->height,
1287 		 mbutton->core.width - XwCASCADEWIDTH -
1288 		         mbutton->primitive.highlight_thickness -
1289 		         mbutton->button.internal_width,
1290 		 mbutton->menubutton.cascade_y);
1291    }
1292 }
1293 
1294 /*************************************<->*************************************
1295  *
1296  *   Inverted (mbutton)
1297  *
1298  *   Description:
1299  *   -----------
1300  *
1301  *   Inputs:
1302  *   ------
1303  *
1304  *   Outputs:
1305  *   -------
1306  *
1307  *   Procedures Called
1308  *   -----------------
1309  *   XFillRectangle
1310  *   DrawLabelMarkCascade
1311  *
1312  *************************************<->***********************************/
1313 
Inverted(mw)1314 static void Inverted (mw)
1315 XwMenuButtonWidget mw;
1316 
1317 {
1318    mw -> menubutton.inverted = TRUE;
1319 
1320    XFillRectangle (XtDisplay (mw), XtWindow (mw),
1321                    mw->button.normal_GC,
1322                    mw -> primitive.highlight_thickness + 1,
1323                    mw -> primitive.highlight_thickness + 1,
1324                    mw -> core.width - 2 *
1325                       (mw -> primitive.highlight_thickness + 1),
1326                    mw -> core.height - 2 *
1327                       (mw -> primitive.highlight_thickness + 1));
1328    DrawLabelMarkCascade (mw);
1329 }
1330 
1331 
1332 
1333 /*************************************<->*************************************
1334  *
1335  *   NonInverted (mbutton)
1336  *
1337  *   Description:
1338  *   -----------
1339  *
1340  *   Inputs:
1341  *   ------
1342  *
1343  *   Outputs:
1344  *   -------
1345  *
1346  *   Procedures Called
1347  *   -----------------
1348  *   XClearWindow
1349  *   DrawLabelMarkCascade
1350  *
1351  *************************************<->***********************************/
1352 
NonInverted(mbutton)1353 static void NonInverted (mbutton)
1354 XwMenuButtonWidget mbutton;
1355 
1356 {
1357    mbutton->menubutton.inverted = FALSE;
1358 
1359    XClearWindow (XtDisplay(mbutton), XtWindow(mbutton));
1360    DrawLabelMarkCascade (mbutton);
1361 }
1362 
1363 
1364 
1365 /*************************************<->*************************************
1366  *
1367  *   Highlight(mbutton)
1368  *
1369  *   Description:
1370  *   -----------
1371  *
1372  *   Inputs:
1373  *   ------
1374  *
1375  *   Outputs:
1376  *   -------
1377  *
1378  *   Procedures Called
1379  *   -----------------
1380  *   Moved
1381  *   Inverted
1382  *
1383  *************************************<->***********************************/
1384 
Highlight(mbutton)1385 static void Highlight (mbutton)
1386 XwMenuButtonWidget mbutton;
1387 {
1388 /*
1389    if (mbutton->primitive.traversal_type == XwHIGHLIGHT_TRAVERSAL)
1390       _XwHighlightBorder(mbutton);
1391    else
1392 */
1393       Inverted (mbutton);
1394 }
1395 
1396 /*************************************<->*************************************
1397  *
1398  *   Unhighlight (mbutton)
1399  *
1400  *   Description:
1401  *   -----------
1402  *
1403  *   Inputs:
1404  *   ------
1405  *
1406  *   Outputs:
1407  *   -------
1408  *
1409  *   Procedures Called
1410  *   -----------------
1411  *   Moved
1412  *   Inverted
1413  *
1414  *************************************<->***********************************/
1415 
Unhighlight(mbutton)1416 static void Unhighlight (mbutton)
1417 XwMenuButtonWidget mbutton;
1418 {
1419 /*
1420    if (mbutton->primitive.traversal_type == XwHIGHLIGHT_TRAVERSAL)
1421       _XwUnhighlightBorder(mbutton);
1422    else
1423 */
1424       NonInverted (mbutton);
1425    mbutton->menubutton.cascadeEnabled = FALSE;
1426 }
1427 
1428 /*************************************<->*************************************
1429  *
1430  *  Enter (w, event)                  PRIVATE
1431  *
1432  *   Description:
1433  *   -----------
1434  *
1435  *   Inputs:
1436  *   ------
1437  *     w           =   widget instance that was selected.
1438  *     event       =   event record
1439  *
1440  *   Outputs:
1441  *   -------
1442  *
1443  *   Procedures Called
1444  *   -----------------
1445  *   Moved
1446  *   Inverted
1447  *
1448  *************************************<->***********************************/
1449 
Enter(w,event)1450 static void Enter(w,event)
1451 Widget w;
1452 XEvent *event;
1453 {
1454    XwMenuButtonWidget mbutton = (XwMenuButtonWidget)w;
1455 
1456 #ifdef DEBUG
1457    printf ("Enter %s\n", w->core.name);
1458 #endif
1459    if ((mbutton->menubutton.menuMgr == NULL) ||
1460        ((*(((XwMenuMgrWidgetClass)
1461 	  XtClass (mbutton->menubutton.menuMgr))->menu_mgr_class.validEvent))
1462 	  (mbutton->menubutton.menuMgr, mbutton, event)))
1463    {
1464       /*
1465        * Check on cascade indicator
1466        */
1467       Moved (w, event);
1468 
1469 /*
1470  *    if (mbutton->primitive.traversal_type != XwHIGHLIGHT_TRAVERSAL)
1471  */
1472 	 Inverted(mbutton);
1473    }
1474 
1475    /* to-do:  if no hintProc is specified, should generate a hint tag */
1476 
1477    if ((mbutton->menubutton.hint != NULL) &&
1478 	 (mbutton->menubutton.hintProc != NULL)) {
1479       mbutton->menubutton.hintProc(mbutton->menubutton.hint);
1480    }
1481 }
1482 
1483 /*************************************<->*************************************
1484  *
1485  *   EnterParentsWindow (menupane, mbutton,event)
1486  *
1487  *   Description:
1488  *   -----------
1489  *
1490  *   Inputs:
1491  *   ------
1492  *
1493  *   Outputs:
1494  *   -------
1495  *
1496  *   Procedures Called
1497  *   -----------------
1498  *
1499  *************************************<->***********************************/
1500 
EnterParentsWindow(menupane,mbutton,event)1501 static void EnterParentsWindow (menupane, mbutton, event)
1502 Widget              menupane;
1503 XwMenuButtonWidget  mbutton;
1504 XEvent 		  * event;
1505 {
1506    Boolean remainHighlighted;
1507    XwunselectParams params;
1508 
1509    XEnterWindowEvent * entEvent = (XEnterWindowEvent *) event;
1510 
1511 #ifdef DEBUG
1512    printf ("EnterParents %s %s ", menupane->core.name, mbutton->core.name);
1513 #endif
1514 
1515    /*
1516     * if outside of the menubutton, bring down submenu.  I am assuming that
1517     * the x parameters are okay.  This means that entering my parents borders
1518     * on the correct y parameters will not cause the unselects to be called.
1519     */
1520    if ((entEvent->y < mbutton->core.y) ||
1521        (entEvent->y > mbutton->core.y + mbutton->core.height +
1522                        2 * mbutton->core.border_width))
1523    {
1524       params.rootX = entEvent->x_root;
1525       params.rootY = entEvent->y_root;
1526       params.remainHighlighted = FALSE;
1527 
1528 #ifdef DEBUG
1529       printf ("rootX %d rootY %d\n", params.rootX, params.rootY);
1530       printf ("disabled\n");
1531 #endif
1532 
1533       XtCallCallbacks ((Widget)mbutton, XtNcascadeUnselect, &params);
1534       mbutton->menubutton.cascadeEnabled = params.remainHighlighted;
1535       if (mbutton->menubutton.cascadeEnabled == FALSE)
1536          Unhighlight (mbutton);
1537    }
1538 /*   else
1539  *    Moved (mbutton, event);
1540  */
1541 
1542 #ifdef DEBUG
1543    printf ("\n");
1544 #endif
1545 
1546    XtRemoveEventHandler (menupane, EnterWindowMask, FALSE,
1547 			 (XtEventHandler)EnterParentsWindow, mbutton);
1548 }
1549 
1550 /*************************************<->*************************************
1551  *
1552  *  Leave (w, event)                  PRIVATE
1553  *
1554  *   Description:
1555  *   -----------
1556  *
1557  *   Inputs:
1558  *   ------
1559  *
1560  *   Outputs:
1561  *   -------
1562  *
1563  *   Procedures Called
1564  *   -----------------
1565  *   XtCallCallbacks
1566  *   NonInverted
1567  *
1568  *************************************<->***********************************/
1569 
Leave(w,event)1570 static void Leave(w,event)
1571 Widget w;
1572 XEvent *event;
1573 
1574 {
1575    XwunselectParams  params;
1576    XwMenuButtonWidget mbutton = (XwMenuButtonWidget)w;
1577    XLeaveWindowEvent * lEvent = (XLeaveWindowEvent *) event;
1578 
1579    params.rootX = lEvent->x_root;
1580    params.rootY = lEvent->y_root;
1581 
1582 
1583    if ((mbutton->menubutton.menuMgr == NULL) ||
1584        ((*(((XwMenuMgrWidgetClass)
1585 	    XtClass (mbutton->menubutton.menuMgr))->menu_mgr_class.validEvent))
1586 	    (mbutton->menubutton.menuMgr, mbutton, event)))
1587    {
1588       if (mbutton->menubutton.cascadeEnabled)
1589       {
1590          params.remainHighlighted = FALSE;
1591          XtCallCallbacks ((Widget)mbutton, XtNcascadeUnselect, &params);
1592          mbutton->menubutton.cascadeEnabled = params.remainHighlighted;
1593 
1594          if (mbutton->menubutton.cascadeEnabled)
1595          {
1596             XtAddEventHandler (XtParent(mbutton), EnterWindowMask, FALSE,
1597       			       (XtEventHandler)EnterParentsWindow, mbutton);
1598             return;
1599          }
1600       }
1601 
1602       if (mbutton->menubutton.inverted)
1603          NonInverted(mbutton);
1604    }
1605 
1606    if ((mbutton->menubutton.hint != NULL) &&
1607 	 (mbutton->menubutton.hintProc != NULL)) {
1608       mbutton->menubutton.hintProc("");
1609    }
1610 }
1611 
1612 /*************************************<->*************************************
1613  *
1614  *   Moved
1615  *
1616  *   Description:
1617  *   -----------
1618  *
1619  *   Inputs:
1620  *   ------
1621  *
1622  *   Outputs:
1623  *   -------
1624  *
1625  *   Procedures Called
1626  *   -----------------
1627  *   XQueryPointer
1628  *   XtCallCallbacks
1629  *
1630  *************************************<->***********************************/
1631 
Moved(w,event)1632 static void Moved (w,event)
1633 Widget   w;
1634 XEvent * event;
1635 
1636 {
1637    XwMenuButtonWidget mbutton = (XwMenuButtonWidget)w;
1638 
1639    int xPosition, yPosition;
1640    int xroot, yroot;
1641    Window root, child;
1642    unsigned int mask;
1643    XwunselectParams params;
1644 
1645    XButtonPressedEvent * buttonEvent = (XButtonPressedEvent *) event;
1646 
1647 #ifdef DEBUG
1648    printf ("Moved %s\n", w->core.name);
1649 #endif
1650 
1651    /*
1652     * only do this if I have a cascade showing
1653     */
1654    if ((mbutton->menubutton.cascadeOn) &&
1655        (mbutton->primitive.traversal_type == XwHIGHLIGHT_OFF))
1656    {
1657       /*
1658        * if there is a menu manager and the cascade has not been popped up,
1659        * then ask the menu manager if it should be popped up
1660        */
1661       if ((mbutton->menubutton.menuMgr == NULL) ||
1662           (mbutton->menubutton.cascadeEnabled == TRUE) ||
1663           (*(((XwMenuMgrWidgetClass)
1664             XtClass(mbutton->menubutton.menuMgr))->menu_mgr_class.doICascade))
1665 	       (mbutton->menubutton.menuMgr, mbutton))
1666       {
1667          /*
1668           * check if the event appears to have occurred in the cascade area
1669           */
1670 	 if ((mbutton->menubutton.cascadeEnabled) ||
1671 	     ((buttonEvent->y > 0) &&
1672 	      (buttonEvent->y < mbutton->core.height +
1673                                 2 * mbutton->core.border_width) &&
1674 	      (buttonEvent->x < mbutton->core.width +
1675                                 2 * mbutton->core.border_width) &&
1676 	      (buttonEvent->x > mbutton->core.width +
1677                                 2 * mbutton->core.border_width -
1678                                 XwCASCADEWIDTH -
1679 	                        mbutton->primitive.highlight_thickness -
1680                                 mbutton->button.internal_width)))
1681 	 {
1682 	    /*
1683 	     * Verify that its really in the cascade area
1684 	     */
1685 	    XQueryPointer (XtDisplay(mbutton), mbutton->core.window,
1686 			   &root, &child, &xroot, &yroot, &xPosition,
1687 			   &yPosition, &mask);
1688 
1689 	    if ((yPosition > 0) &&
1690 		(yPosition < mbutton->core.height +
1691                              2 * mbutton->core.border_width) &&
1692 		(xPosition < mbutton->core.width +
1693                              2 * mbutton->core.border_width) &&
1694 		(xPosition > mbutton->core.width +
1695                              2 * mbutton->core.border_width - XwCASCADEWIDTH -
1696 		             mbutton->primitive.highlight_thickness -
1697                              mbutton->button.internal_width))
1698 	    {
1699 	       if (!mbutton->menubutton.cascadeEnabled)
1700 	       {
1701 		  XtCallCallbacks ((Widget)mbutton, XtNcascadeSelect, NULL);
1702 #ifdef DEBUG
1703                   printf ("enabled\n");
1704 #endif
1705 		  mbutton->menubutton.cascadeEnabled = TRUE;
1706 	       }
1707 	    }
1708 	    else if (mbutton->menubutton.cascadeEnabled)
1709 	    {
1710                params.rootX = xroot;
1711  	       params.rootY = yroot;
1712 	       params.remainHighlighted = FALSE;
1713 #ifdef DEBUG
1714 	       printf ("Moved rootX %d rootY %d\n", params.rootX, params.rootY);
1715 #endif
1716 	       XtCallCallbacks ((Widget)mbutton, XtNcascadeUnselect, &params);
1717 	       mbutton->menubutton.cascadeEnabled = params.remainHighlighted;
1718 	    }
1719 	 }
1720       }
1721    }
1722 }
1723 
1724 /*************************************<->*************************************
1725  *
1726  *  Redisplay (w, event)
1727  *
1728  *   Description:
1729  *   -----------
1730  *     Cause the widget, identified by w, to be redisplayed.
1731  *
1732  *   Inputs:
1733  *   ------
1734  *     w = widget to be redisplayed;
1735  *     event = event structure identifying need for redisplay on this
1736  *             widget.
1737  *
1738  *   Outputs:
1739  *   -------
1740  *
1741  *   Procedures Called
1742  *   -----------------
1743  *   Inverted
1744  *   NonInverted
1745  *   _XwHighlightBorder
1746  *   _XwUnhighlightBorder
1747  *
1748  *************************************<->***********************************/
1749 
Redisplay(w,event)1750 static void Redisplay(w, event)
1751     Widget w;
1752     XEvent *event;
1753 {
1754    XwMenuButtonWidget mbutton = (XwMenuButtonWidget) w;
1755 
1756    /*
1757     * if the highlight state has changed since the last redisplay,
1758     * update the window and set the font GC.
1759     */
1760    if (mbutton->menubutton.inverted)
1761       Inverted(mbutton);
1762 
1763    else
1764       NonInverted(mbutton);
1765 
1766    if (mbutton->primitive.highlighted)
1767       _XwHighlightBorder(mbutton);
1768 
1769    else
1770       if (mbutton->primitive.display_highlighted)
1771 	 _XwUnhighlightBorder(mbutton);
1772 }
1773 
1774 /*************************************<->*************************************
1775  *
1776  *  SetValues(urrent, request, new)
1777  *
1778  *   Description:
1779  *   -----------
1780  *     This is the set values procedure for the menubutton class.  It is
1781  *     called last (the set values rtnes for its superclasses are called
1782  *     first).
1783  *
1784  *
1785  *   Inputs:
1786  *   ------
1787  *    current = original widget;
1788  *    request = copy of current (?);
1789  *    new = copy of request which reflects changes made to it by
1790  *          set values procedures of its superclasses;
1791  *
1792  *   Outputs:
1793  *   -------
1794  *
1795  *   Procedures Called
1796  *   -----------------
1797  *
1798  *************************************<->***********************************/
1799 
SetValues(current,request,new)1800 static Boolean SetValues (current, request, new)
1801 Widget current, request, new;
1802 {
1803     XtWidgetGeometry	reqGeo;
1804     XtWidgetGeometry	replyGeo;
1805     XwMenuButtonWidget 	curmbutton = (XwMenuButtonWidget) current;
1806     XwMenuButtonWidget 	newmbutton  = (XwMenuButtonWidget) new;
1807     Boolean  		flag = FALSE;    /* our return value */
1808     Dimension	        dim;
1809     KeySym              tempKeysym;
1810 
1811     /* We never allow our traversal state to change using SetValues() */
1812     newmbutton->primitive.traversal_type = curmbutton->primitive.traversal_type;
1813 
1814     /*
1815      * If the accelerator string changed, malloc space for the string
1816      * and copy it to our space.  The old string must be freed.
1817      */
1818 
1819     if (curmbutton->menubutton.accelerator !=
1820 	newmbutton->menubutton.accelerator)
1821     {
1822        if (newmbutton->menubutton.accelerator)
1823        {
1824 	  if (_XwMapKeyEvent (newmbutton->menubutton.accelerator,
1825 			      &newmbutton->menubutton.accelEventType,
1826 			      &tempKeysym,
1827 			      &newmbutton->menubutton.accelModifiers)
1828 	      == FALSE)
1829 	  {
1830 	     /* Invalid string; revert to previous one */
1831 	     XtWarning
1832 		("MenuButton: Invalid accelerator; using previous setting");
1833 	     newmbutton->menubutton.accelerator =
1834 		curmbutton->menubutton.accelerator;
1835 	     newmbutton->menubutton.accelEventType =
1836 		curmbutton->menubutton.accelEventType;
1837 	     newmbutton->menubutton.accelDetail =
1838 		curmbutton->menubutton.accelDetail;
1839 	     newmbutton->menubutton.accelModifiers =
1840 		curmbutton->menubutton.accelModifiers;
1841 	  }
1842 	  else
1843 	  {
1844 	     /* valid string */
1845              newmbutton->menubutton.accelDetail = XKeysymToKeycode (
1846                     XtDisplay(newmbutton), tempKeysym);
1847 	     newmbutton->menubutton.accelerator =
1848 		strcpy(XtMalloc((unsigned)
1849 			   (XwStrlen(newmbutton->menubutton.accelerator)+1)),
1850 		       newmbutton->menubutton.accelerator);
1851 
1852 	     if (newmbutton->menubutton.menuMgr)
1853 		(*(((XwMenuMgrWidgetClass)
1854 		    XtClass (newmbutton->menubutton.menuMgr))->
1855 		       menu_mgr_class.setSelectAccelerator))
1856 		   (newmbutton->menubutton.menuMgr, (Widget)newmbutton,
1857 		    newmbutton->menubutton.accelerator,
1858 		    newmbutton->menubutton.accelEventType,
1859 		    newmbutton->menubutton.accelDetail,
1860 		    newmbutton->menubutton.accelModifiers);
1861 
1862 	     if (curmbutton->menubutton.accelerator)
1863 		XtFree ((char *) curmbutton->menubutton.accelerator);
1864 	  }
1865        }
1866        else if (curmbutton->menubutton.accelerator)
1867        {
1868 	  if (curmbutton->menubutton.menuMgr)
1869 	     (*(((XwMenuMgrWidgetClass)
1870 		 XtClass(curmbutton->menubutton.menuMgr))->
1871 		          menu_mgr_class.clearSelectAccelerator))
1872 		    (curmbutton->menubutton.menuMgr, (Widget)curmbutton);
1873 
1874 	  XtFree ((char *) curmbutton->menubutton.accelerator);
1875        }
1876     }
1877 
1878     /*
1879      * Determine if the mnemonic changed, verify and malloc space.
1880      * Notify menuMgr of the change.
1881      */
1882 
1883     if (curmbutton->menubutton.mnemonic != newmbutton->menubutton.mnemonic)
1884     {
1885       if (newmbutton->menubutton.mnemonic)
1886       {
1887          if (*(newmbutton->menubutton.mnemonic) == '\0')
1888          {
1889             XtWarning
1890               ("MenuButton: Invalid mnemonic; using previous setting");
1891             newmbutton->menubutton.mnemonic = curmbutton->menubutton.mnemonic;
1892          }
1893          else
1894          {
1895             char mne = newmbutton->menubutton.mnemonic[0];
1896 
1897             newmbutton->menubutton.mnemonic = (String)XtMalloc(2);
1898             newmbutton->menubutton.mnemonic[0] = mne;
1899             newmbutton->menubutton.mnemonic[1] = '\0';
1900 
1901  	    if (newmbutton->menubutton.menuMgr)
1902 	       (*(((XwMenuMgrWidgetClass)
1903 		    XtClass (newmbutton->menubutton.menuMgr))->
1904 		       menu_mgr_class.setSelectMnemonic))
1905 		   (newmbutton->menubutton.menuMgr, (Widget)newmbutton,
1906                     newmbutton->menubutton.mnemonic);
1907 
1908             XtFree (curmbutton->menubutton.mnemonic);
1909          }
1910       }
1911       else
1912       {
1913 	 if (newmbutton->menubutton.menuMgr)
1914 	    (*(((XwMenuMgrWidgetClass)
1915 		 XtClass (curmbutton->menubutton.menuMgr))->
1916 		    menu_mgr_class.clearSelectMnemonic))
1917 		(curmbutton->menubutton.menuMgr, (Widget)curmbutton);
1918 
1919          XtFree(curmbutton->menubutton.mnemonic);
1920       }
1921     }
1922 
1923     /*
1924      * recalculate the underline parameters if mnemonic or font changes
1925      */
1926     if ((newmbutton->menubutton.mnemonic != curmbutton->menubutton.mnemonic) ||
1927 	(newmbutton->button.font != curmbutton->button.font))
1928     {
1929        SetUnderline (newmbutton);
1930        flag = TRUE;
1931     }
1932 
1933 
1934     /*
1935      * If the foreground or background changed, or the color or stipple
1936      * declaration was changed, recreate the GC's
1937      */
1938     if ((newmbutton->primitive.foreground !=
1939             curmbutton->primitive.foreground) ||
1940         (newmbutton->core.background_pixel !=
1941             curmbutton->core.background_pixel) ||
1942 	(newmbutton->menubutton.rectColor !=
1943 	    curmbutton->menubutton.rectColor) ||
1944 	(newmbutton->menubutton.rectStipple !=
1945 	    curmbutton->menubutton.rectStipple))
1946     {
1947        GetGC (newmbutton);
1948        XtDestroyGC (curmbutton->menubutton.defPixmap_GC);
1949        XtDestroyGC (curmbutton->menubutton.invertPixmap_GC);
1950     }
1951 
1952     /*
1953      * If the GCs are new, or the images are new, create new pixmaps
1954      */
1955     if ((newmbutton->menubutton.markImage !=
1956             curmbutton->menubutton.markImage) ||
1957         (newmbutton->primitive.foreground !=
1958             curmbutton->primitive.foreground) ||
1959         (newmbutton->core.background_pixel !=
1960             curmbutton->core.background_pixel))
1961     {
1962        if (!newmbutton->menubutton.markImage)
1963 	  newmbutton->menubutton.markImage =
1964 	     newmbutton->menubutton.defMarkImage;
1965 
1966        CreatePixmap(newmbutton, newmbutton->menubutton.markImage,
1967 		    &newmbutton->menubutton.markPixmap,
1968 		    &newmbutton->menubutton.invertMarkPixmap);
1969        flag = TRUE;
1970     }
1971 
1972     if ((newmbutton->menubutton.cascadeImage !=
1973 	    curmbutton->menubutton.cascadeImage) ||
1974         (newmbutton->primitive.foreground !=
1975             curmbutton->primitive.foreground) ||
1976         (newmbutton->core.background_pixel !=
1977             curmbutton->core.background_pixel))
1978     {
1979        if (!newmbutton->menubutton.cascadeImage)
1980 	  newmbutton->menubutton.cascadeImage =
1981 	     newmbutton->menubutton.defCascadeImage;
1982 
1983        CreatePixmap(newmbutton, newmbutton->menubutton.cascadeImage,
1984 		    &newmbutton->menubutton.cascadePixmap,
1985 		    &newmbutton->menubutton.invertCascadePixmap);
1986        flag = TRUE;
1987     }
1988 
1989     if ((newmbutton->menubutton.labelImage !=
1990 	    curmbutton->menubutton.labelImage) ||
1991         (newmbutton->primitive.foreground !=
1992             curmbutton->primitive.foreground) ||
1993         (newmbutton->core.background_pixel !=
1994             curmbutton->core.background_pixel))
1995     {
1996        CreatePixmap(newmbutton, newmbutton->menubutton.labelImage,
1997 		    &newmbutton->menubutton.labelPixmap,
1998 		    &newmbutton->menubutton.invertLabelPixmap);
1999 
2000        if (newmbutton->menubutton.labelType == XwIMAGE)
2001 	  flag = TRUE;
2002     }
2003 
2004     if ((newmbutton->core.sensitive != curmbutton->core.sensitive) ||
2005        (newmbutton->core.ancestor_sensitive !=
2006                         curmbutton->core.ancestor_sensitive))
2007     {
2008 	if (curmbutton->menubutton.menuMgr)
2009         {
2010 	   (*(((XwMenuMgrWidgetClass)
2011 	     XtClass(curmbutton->menubutton.menuMgr))->
2012 	             menu_mgr_class.btnSensitivityChanged))
2013 	      (curmbutton->menubutton.menuMgr, (Widget)newmbutton);
2014         }
2015     }
2016 
2017     /*
2018      * fields that change that cause a redraw
2019      */
2020     if 	((newmbutton->menubutton.labelType !=
2021 	     curmbutton->menubutton.labelType) ||
2022 	 (newmbutton->menubutton.setMark !=
2023 	     curmbutton->menubutton.setMark) ||
2024 	 (newmbutton->menubutton.cascadeOn !=
2025 	     curmbutton->menubutton.cascadeOn) ||
2026 	 (newmbutton->menubutton.mgrOverrideMnemonic !=
2027 	     curmbutton->menubutton.mgrOverrideMnemonic) ||
2028          (newmbutton->menubutton.rectColor !=
2029              curmbutton->menubutton.rectColor) ||
2030          (newmbutton->menubutton.rectStipple !=
2031              curmbutton->menubutton.rectStipple))
2032 
2033 
2034        flag = TRUE;
2035 
2036 
2037     /**********************************************************************
2038      * Calculate the window size:  The assumption here is that if
2039      * the width and height are the same in the new and current instance
2040      * record that those fields were not changed with set values.  Therefore
2041      * its okay to recompute the necessary width and height.  However, if
2042      * the new and current do have different width/heights then leave them
2043      * alone because that's what the user wants.
2044      *********************************************************************/
2045 
2046     /* "noPad" option prevents button from resizing itself  2/24/00 --Tim */
2047 
2048     if (curmbutton->core.width == request->core.width &&
2049 	  curmbutton->menubutton.noPad == False)
2050     {
2051        IdealWidth (newmbutton, &newmbutton->core.width);
2052        flag = TRUE;
2053     }
2054     else if (request->core.width <= 0)
2055     {
2056        XtWarning ("MenuButton:  Invalid width; using previous setting");
2057        newmbutton->core.width = curmbutton->core.width;
2058     }
2059 
2060     if (curmbutton->core.height == request->core.height &&
2061 	  curmbutton->menubutton.noPad == False)
2062     {
2063        newmbutton->core.height = ComputeHeight(newmbutton);
2064        flag = TRUE;
2065     }
2066     else if (request->core.height <= 0)
2067     {
2068        XtWarning ("MenuButton:  Invalid height; using previous setting");
2069        newmbutton->core.height = curmbutton->core.height;
2070     }
2071 
2072     return (flag);
2073 }
2074 
2075 /*************************************<->*************************************
2076  *
2077  *  Resize(w)
2078  *
2079  *   Description:
2080  *   -----------
2081  *     A resize event has been generated. Recompute location of button
2082  *     elements.
2083  *
2084  *   Inputs:
2085  *   ------
2086  *     w  = widget to be resized.
2087  *
2088  *   Outputs:
2089  *   -------
2090  *
2091  *   Procedures Called
2092  *   -----------------
2093  *
2094  *************************************<->***********************************/
2095 
Resize(w)2096 static void Resize(w)
2097    Widget w;
2098 {
2099 
2100    XwMenuButtonWidget mbutton = (XwMenuButtonWidget) w;
2101 
2102    ComputeVertical(mbutton);
2103    SetUnderline(mbutton);
2104 }
2105 
2106 
2107 /*************************************<->*************************************
2108  *
2109  *  SetTraversalType(w)
2110  *
2111  *   Description:
2112  *   -----------
2113  *
2114  *   Inputs:
2115  *   ------
2116  *
2117  *   Outputs:
2118  *   -------
2119  *
2120  *   Procedures Called
2121  *   -----------------
2122  *
2123  *************************************<->***********************************/
2124 
SetTraversalType(w,highlight_mode)2125 static void SetTraversalType (w, highlight_mode)
2126 
2127    Widget w;
2128    int highlight_mode;
2129 
2130 {
2131 
2132    XwMenuButtonWidget mbutton = (XwMenuButtonWidget) w;
2133 
2134    mbutton->primitive.traversal_type = highlight_mode;
2135 
2136    if (highlight_mode == XwHIGHLIGHT_TRAVERSAL)
2137    {
2138       XtAugmentTranslations (w, XwprimitiveClassRec.primitive_class.
2139                                 translations);
2140       w->core.widget_class->core_class.visible_interest = True;
2141    }
2142 }
2143 
2144 
2145 /*************************************<->*************************************
2146  *
2147  *  TraverseRight(w, event)
2148  *
2149  *   Description:
2150  *   -----------
2151  *
2152  *   Inputs:
2153  *   ------
2154  *
2155  *   Outputs:
2156  *   -------
2157  *
2158  *   Procedures Called
2159  *   -----------------
2160  *
2161  *************************************<->***********************************/
2162 
TraverseRight(w,event)2163 static void TraverseRight (w, event)
2164 
2165    XwMenuButtonWidget w;
2166    XEvent * event;
2167 
2168 {
2169    /*
2170     * Ask the menu manager to traverse to the next menupane, if we
2171     * have a cascade.
2172     */
2173 
2174    if ((w->menubutton.cascadeOn) && (w->menubutton.menuMgr) &&
2175        (w->primitive.I_have_traversal) && (_XwUniqueEvent (event)))
2176    {
2177       (*(((XwMenuMgrWidgetClass)
2178         XtClass(w->menubutton.menuMgr))->menu_mgr_class.traverseRight))
2179         (w->menubutton.menuMgr, event);
2180    }
2181 }
2182 
2183 
2184 /*************************************<->*************************************
2185  *
2186  *  TraverseLeft(w, event)
2187  *
2188  *   Description:
2189  *   -----------
2190  *
2191  *   Inputs:
2192  *   ------
2193  *
2194  *   Outputs:
2195  *   -------
2196  *
2197  *   Procedures Called
2198  *   -----------------
2199  *
2200  *************************************<->***********************************/
2201 
TraverseLeft(w,event)2202 static void TraverseLeft (w, event)
2203 
2204    XwMenuButtonWidget w;
2205    XEvent * event;
2206 
2207 {
2208    /*
2209     * Ask the menu manager to traverse to the previous menupane.
2210     */
2211 
2212    if ((w->menubutton.menuMgr) && (_XwUniqueEvent (event)) &&
2213        (w->primitive.I_have_traversal))
2214    {
2215       (*(((XwMenuMgrWidgetClass)
2216         XtClass(w->menubutton.menuMgr))->menu_mgr_class.traverseLeft))
2217         (w->menubutton.menuMgr, event);
2218    }
2219 }
2220 
2221 
2222 /*************************************<->*************************************
2223  *
2224  *  TraverseNext(w, event)
2225  *
2226  *   Description:
2227  *   -----------
2228  *
2229  *   Inputs:
2230  *   ------
2231  *
2232  *   Outputs:
2233  *   -------
2234  *
2235  *   Procedures Called
2236  *   -----------------
2237  *
2238  *************************************<->***********************************/
2239 
TraverseNext(w,event)2240 static void TraverseNext (w, event)
2241 
2242    XwMenuButtonWidget w;
2243    XEvent * event;
2244 
2245 {
2246    /*
2247     * Ask the menu manager to traverse to the previous menupane.
2248     */
2249 
2250    if ((w->menubutton.menuMgr) && (_XwUniqueEvent (event)) &&
2251        (w->primitive.I_have_traversal))
2252    {
2253       (*(((XwMenuMgrWidgetClass)
2254         XtClass(w->menubutton.menuMgr))->menu_mgr_class.traverseNext))
2255         (w->menubutton.menuMgr, event);
2256    }
2257 }
2258 
2259 
2260 /*************************************<->*************************************
2261  *
2262  *  TraversePrev(w, event)
2263  *
2264  *   Description:
2265  *   -----------
2266  *
2267  *   Inputs:
2268  *   ------
2269  *
2270  *   Outputs:
2271  *   -------
2272  *
2273  *   Procedures Called
2274  *   -----------------
2275  *
2276  *************************************<->***********************************/
2277 
TraversePrev(w,event)2278 static void TraversePrev (w, event)
2279 
2280    XwMenuButtonWidget w;
2281    XEvent * event;
2282 
2283 {
2284    /*
2285     * Ask the menu manager to traverse to the previous menupane.
2286     */
2287 
2288    if ((w->menubutton.menuMgr) && (_XwUniqueEvent (event)) &&
2289        (w->primitive.I_have_traversal))
2290    {
2291       (*(((XwMenuMgrWidgetClass)
2292         XtClass(w->menubutton.menuMgr))->menu_mgr_class.traversePrev))
2293         (w->menubutton.menuMgr, event);
2294    }
2295 }
2296 
2297 
2298 /*************************************<->*************************************
2299  *
2300  *  TraverseHome(w)
2301  *
2302  *   Description:
2303  *   -----------
2304  *
2305  *   Inputs:
2306  *   ------
2307  *
2308  *   Outputs:
2309  *   -------
2310  *
2311  *   Procedures Called
2312  *   -----------------
2313  *
2314  *************************************<->***********************************/
2315 
TraverseHome(w,event)2316 static void TraverseHome (w, event)
2317 
2318    XwMenuButtonWidget w;
2319    XEvent * event;
2320 
2321 {
2322    /*
2323     * Ask the menu manager to traverse to the first menupane.
2324     */
2325 
2326    if ((w->menubutton.menuMgr) && (_XwUniqueEvent (event)) &&
2327        (w->primitive.I_have_traversal))
2328    {
2329       (*(((XwMenuMgrWidgetClass)
2330         XtClass(w->menubutton.menuMgr))->menu_mgr_class.traverseHome))
2331         (w->menubutton.menuMgr, event);
2332    }
2333 }
2334 
2335 
2336 /*************************************<->*************************************
2337  *
2338  *  TraverseUp(w)
2339  *
2340  *   Description:
2341  *   -----------
2342  *
2343  *   Inputs:
2344  *   ------
2345  *
2346  *   Outputs:
2347  *   -------
2348  *
2349  *   Procedures Called
2350  *   -----------------
2351  *
2352  *************************************<->***********************************/
2353 
TraverseUp(w,event)2354 static void TraverseUp (w, event)
2355 
2356    XwMenuButtonWidget w;
2357    XEvent * event;
2358 
2359 {
2360    /*
2361     * Ask the menu manager to traverse up one menu button
2362     */
2363 
2364    if ((w->menubutton.menuMgr) && (_XwUniqueEvent (event)) &&
2365        (w->primitive.I_have_traversal))
2366    {
2367       (*(((XwMenuMgrWidgetClass)
2368         XtClass(w->menubutton.menuMgr))->menu_mgr_class.traverseUp))
2369         (w->menubutton.menuMgr, event);
2370    }
2371 }
2372 
2373 
2374 /*************************************<->*************************************
2375  *
2376  *  TraverseDown(w)
2377  *
2378  *   Description:
2379  *   -----------
2380  *
2381  *   Inputs:
2382  *   ------
2383  *
2384  *   Outputs:
2385  *   -------
2386  *
2387  *   Procedures Called
2388  *   -----------------
2389  *
2390  *************************************<->***********************************/
2391 
TraverseDown(w,event)2392 static void TraverseDown (w, event)
2393 
2394    XwMenuButtonWidget w;
2395    XEvent * event;
2396 
2397 {
2398    /*
2399     * Ask the menu manager to traverse down one menu button
2400     */
2401 
2402    if ((w->menubutton.menuMgr) && (_XwUniqueEvent (event)) &&
2403        (w->primitive.I_have_traversal))
2404    {
2405       (*(((XwMenuMgrWidgetClass)
2406         XtClass(w->menubutton.menuMgr))->menu_mgr_class.traverseDown))
2407         (w->menubutton.menuMgr, event);
2408    }
2409 }
2410 
2411 
2412 /*************************************<->*************************************
2413  *
2414  *  TraverseNextTop(w)
2415  *
2416  *   Description:
2417  *   -----------
2418  *
2419  *   Inputs:
2420  *   ------
2421  *
2422  *   Outputs:
2423  *   -------
2424  *
2425  *   Procedures Called
2426  *   -----------------
2427  *
2428  *************************************<->***********************************/
2429 
TraverseNextTop(w,event)2430 static void TraverseNextTop (w, event)
2431 
2432    XwMenuButtonWidget w;
2433    XEvent * event;
2434 
2435 {
2436    /*
2437     * Ask the menu manager to traverse to the next top level menupane
2438     */
2439 
2440    if ((w->menubutton.menuMgr) && (_XwUniqueEvent (event)) &&
2441        (w->primitive.I_have_traversal))
2442    {
2443       (*(((XwMenuMgrWidgetClass)
2444         XtClass(w->menubutton.menuMgr))->menu_mgr_class.traverseNextTop))
2445         (w->menubutton.menuMgr, event);
2446    }
2447 }
2448 
2449 
2450 /************************************************************************
2451  *
2452  *  _XwExtractTime
2453  *     Extract the time field from the event structure.
2454  *
2455  ************************************************************************/
2456 
_XwExtractTime(event)2457 static Time _XwExtractTime (event)
2458 
2459    XEvent * event;
2460 
2461 {
2462    if ((event->type == ButtonPress) || (event->type == ButtonRelease))
2463       return (event->xbutton.time);
2464 
2465    if ((event->type == KeyPress) || (event->type == KeyRelease))
2466       return (event->xkey.time);
2467 
2468    return ((Time) 0);
2469 }
2470 
2471 
_XwUniqueEvent(event)2472 Boolean _XwUniqueEvent (event)
2473 
2474    XEvent * event;
2475 
2476 {
2477    static unsigned long serial = 0;
2478    static Time time = 0;
2479    static int type = 0;
2480    Time newTime;
2481 
2482    /*
2483     * Ignore duplicate events, caused by an event being dispatched
2484     * to both the focus widget and the spring-loaded widget, where
2485     * these map to the same widget (menus).
2486     */
2487    if ((time != (newTime = _XwExtractTime (event))) ||
2488        (type != event->type) ||
2489        (serial != event->xany.serial))
2490    {
2491       /* Save the fingerprints for the new event */
2492       type = event->type;
2493       serial = event->xany.serial;
2494       time = newTime;
2495 
2496       return (TRUE);
2497    }
2498 
2499    return (FALSE);
2500 }
2501 
2502 
2503 /*************************************<->*************************************
2504  *
2505  *  Visibility(parameters)
2506  *
2507  *   Description:
2508  *   -----------
2509  *     xxxxxxxxxxxxxxxxxxxxxxx
2510  *
2511  *
2512  *   Inputs:
2513  *   ------
2514  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
2515  *
2516  *   Outputs:
2517  *   -------
2518  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
2519  *
2520  *   Procedures Called
2521  *   -----------------
2522  *
2523  *************************************<->***********************************/
2524 
Visibility(widget,event)2525 static void Visibility (widget, event)
2526 
2527    Widget widget;
2528    XEvent * event;
2529 
2530 {
2531    /*
2532     * Noop; purpose is to prevent Primitive's translation from
2533     * taking effect.
2534     */
2535 }
2536 
2537 
2538 /*************************************<->*************************************
2539  *
2540  *  Unmap(parameters)
2541  *
2542  *   Description:
2543  *   -----------
2544  *     xxxxxxxxxxxxxxxxxxxxxxx
2545  *
2546  *
2547  *   Inputs:
2548  *   ------
2549  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
2550  *
2551  *   Outputs:
2552  *   -------
2553  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
2554  *
2555  *   Procedures Called
2556  *   -----------------
2557  *
2558  *************************************<->***********************************/
2559 
Unmap(widget,event)2560 static void Unmap (widget, event)
2561 
2562    Widget widget;
2563    XEvent * event;
2564 
2565 {
2566    /*
2567     * Noop; purpose is to prevent Primitive's translation from
2568     * taking effect.
2569     */
2570 }
2571