1 /*************************************<+>*************************************
2 *****************************************************************************
8 ** Description: Contains code for primitive widget class: MenuButton
10 *****************************************************************************
12 ** Copyright (c) 1988 by Hewlett-Packard Company
13 ** Copyright (c) 1988 by the Massachusetts Institute of Technology
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
24 *****************************************************************************
25 *************************************<+>*************************************/
33 * Include files & Static Routine Definitions
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>
43 #include <Xw/MenuBtnP.h>
44 #include <Xw/MenuBtn.h>
47 #include <X11/XHPlib.h>
51 #define XtRWidget XtRPointer
54 static void Redisplay();
55 static Boolean
SetValues();
56 static void ClassPartInitialize();
57 static void Inverted();
58 static void NonInverted();
63 static void Initialize();
64 static void Destroy();
65 static void Realize();
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();
83 static void Visibility();
84 Boolean
_XwUniqueEvent();
86 /*************************************<->*************************************
89 * Description: default translation table for class: MenuButton
92 * Matches events with string descriptors for internal routines.
94 *************************************<->***********************************/
97 static char defaultTranslations
[] =
98 "<Btn1Down>: select()\n\
99 <Visible>: visibility()\n\
101 <EnterWindow>: enter()\n\
102 <LeaveWindow>: leave()\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()";
116 /*************************************<->*************************************
119 * Description: action list for class: MenuButton
122 * Matches string descriptors with internal routines.
124 *************************************<->***********************************/
126 static XtActionsRec actionsList
[] =
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
},
144 /*************************************<->*************************************
147 * Description: resource list for class: MenuButton
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.
154 *************************************<->***********************************/
156 static XtResource resources
[] =
159 XtNborderWidth
, XtCBorderWidth
,XtRDimension
, sizeof(Dimension
),
160 XtOffset(XwMenuButtonWidget
, core
.border_width
),
165 XtNlabelType
, XtCLabelType
, XtRLabelType
, sizeof(int),
166 XtOffset(XwMenuButtonWidget
, menubutton
.labelType
),
171 XtNlabelImage
, XtCLabelImage
, XtRImage
, sizeof(XImage
*),
172 XtOffset(XwMenuButtonWidget
, menubutton
.labelImage
),
177 XtNrectColor
, XtCRectColor
, XtRPixel
, sizeof(Pixel
),
178 XtOffset(XwMenuButtonWidget
, menubutton
.rectColor
),
183 XtNrectStipple
, XtCRectStipple
, XtRPixmap
, sizeof(Pixmap
),
184 XtOffset(XwMenuButtonWidget
, menubutton
.rectStipple
),
189 XtNcascadeImage
, XtCCascadeImage
, XtRImage
, sizeof(XImage
*),
190 XtOffset(XwMenuButtonWidget
, menubutton
.cascadeImage
),
195 XtNmarkImage
, XtCMarkImage
, XtRImage
, sizeof(XImage
*),
196 XtOffset(XwMenuButtonWidget
, menubutton
.markImage
),
201 XtNsetMark
, XtCSetMark
, XtRBoolean
, sizeof(Boolean
),
202 XtOffset(XwMenuButtonWidget
, menubutton
.setMark
),
207 XtNnoPad
, XtCNoPad
, XtRBoolean
, sizeof(Boolean
),
208 XtOffset(XwMenuButtonWidget
, menubutton
.noPad
),
213 XtNcascadeOn
, XtCCascadeOn
, XtRWidget
, sizeof(Widget
),
214 XtOffset(XwMenuButtonWidget
, menubutton
.cascadeOn
),
219 XtNkbdAccelerator
, XtCKbdAccelerator
, XtRString
, sizeof(caddr_t
),
220 XtOffset(XwMenuButtonWidget
, menubutton
.accelerator
),
225 XtNhint
, XtCHint
, XtRString
, sizeof(caddr_t
),
226 XtOffset(XwMenuButtonWidget
, menubutton
.hint
),
231 XtNhintProc
, XtCHintProc
, XtRFunction
, sizeof(XwStrProc
),
232 XtOffset(XwMenuButtonWidget
, menubutton
.hintProc
),
237 XtNmgrOverrideMnemonic
, XtCMgrOverrideMnemonic
, XtRBoolean
,
239 XtOffset(XwMenuButtonWidget
, menubutton
.mgrOverrideMnemonic
),
244 XtNmnemonic
, XtCMnemonic
, XtRString
, sizeof(caddr_t
),
245 XtOffset(XwMenuButtonWidget
, menubutton
.mnemonic
),
250 XtNhighlightStyle
, XtCHighlightStyle
, XtRHighlightStyle
, sizeof (int),
251 XtOffset (XwPrimitiveWidget
, primitive
.highlight_style
),
252 XtRString
, "widget_defined"
256 XtNcascadeSelect
, XtCCallback
, XtRCallback
, sizeof(caddr_t
),
257 XtOffset (XwMenuButtonWidget
, menubutton
.cascadeSelect
),
258 XtRPointer
, (caddr_t
) NULL
262 XtNcascadeUnselect
, XtCCallback
, XtRCallback
, sizeof(caddr_t
),
263 XtOffset (XwMenuButtonWidget
, menubutton
.cascadeUnselect
),
264 XtRPointer
, (caddr_t
) NULL
268 XtNmenuMgrId
, XtCMenuMgrId
, XtRWidget
, sizeof(Widget
),
269 XtOffset (XwMenuButtonWidget
, menubutton
.menuMgr
),
274 /*************************************<->*************************************
277 * Description: global class record for instances of class: MenuButton
280 * Defines default field settings for this class record.
282 *************************************<->***********************************/
284 XwMenuButtonClassRec XwmenubuttonClassRec
=
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
,
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
,
316 /* tm_table */ defaultTranslations
,
317 /* query_geometry */ NULL
, /* FIX ME LATER */
318 /* display_accelerator */ XtInheritDisplayAccelerator
,
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
,
331 /* button class fields */ 0,
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
346 WidgetClass XwmenubuttonWidgetClass
= (WidgetClass
)&XwmenubuttonClassRec
;
347 WidgetClass XwmenuButtonWidgetClass
= (WidgetClass
)&XwmenubuttonClassRec
;
350 /*************************************<->*************************************
352 * SetCascadeEnabled (mbutton)
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.
361 * mbutton = this menubutton widget
369 *************************************<->***********************************/
370 static void SetCascadeEnabled (mbutton
)
371 XwMenuButtonWidget mbutton
;
373 mbutton
->menubutton
.cascadeEnabled
= TRUE
;
376 /*************************************<->*************************************
378 * ClearCascadeEnabled (mbutton)
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.
387 * mbutton = this menubutton widget
395 *************************************<->***********************************/
396 static void ClearCascadeEnabled (mbutton
)
397 XwMenuButtonWidget mbutton
;
399 mbutton
->menubutton
.cascadeEnabled
= FALSE
;
402 /*************************************<->*************************************
404 * ClassPartInitialize (parameters)
419 *************************************<->***********************************/
421 static void ClassPartInitialize (wc
)
423 register XwMenuButtonWidgetClass wc
;
426 register XwMenuButtonWidgetClass super
=
427 (XwMenuButtonWidgetClass
) wc
->core_class
.superclass
;
429 if (wc
->menubutton_class
.idealWidthProc
== XtInheritIdealWidthProc
)
430 wc
->menubutton_class
.idealWidthProc
=
431 super
->menubutton_class
.idealWidthProc
;
433 if (wc
->menubutton_class
.unhighlightProc
== XtInheritUnhighlightProc
)
434 wc
->menubutton_class
.unhighlightProc
=
435 super
->menubutton_class
.unhighlightProc
;
437 if (wc
->menubutton_class
.highlightProc
== XtInheritHighlightProc
)
438 wc
->menubutton_class
.highlightProc
=
439 super
->menubutton_class
.highlightProc
;
441 if (wc
->menubutton_class
.setCascadeProc
== XtInheritSetCascadeProc
)
442 wc
->menubutton_class
.setCascadeProc
=
443 super
->menubutton_class
.setCascadeProc
;
445 if (wc
->menubutton_class
.clearCascadeProc
== XtInheritClearCascadeProc
)
446 wc
->menubutton_class
.clearCascadeProc
=
447 super
->menubutton_class
.clearCascadeProc
;
449 if (wc
->menubutton_class
.enterParentProc
== XtInheritEnterParentProc
)
450 wc
->menubutton_class
.enterParentProc
=
451 super
->menubutton_class
.enterParentProc
;
453 if (wc
->menubutton_class
.cascadeSelectProc
== XtInheritCascadeSelectProc
)
454 wc
->menubutton_class
.cascadeSelectProc
=
455 super
->menubutton_class
.cascadeSelectProc
;
457 if (wc
->menubutton_class
.cascadeUnselectProc
== XtInheritCascadeUnselectProc
)
458 wc
->menubutton_class
.cascadeUnselectProc
=
459 super
->menubutton_class
.cascadeUnselectProc
;
461 if (wc
->menubutton_class
.setTraversalType
== XtInheritSetTraversalTypeProc
)
462 wc
->menubutton_class
.setTraversalType
=
463 super
->menubutton_class
.setTraversalType
;
467 /*************************************<->*************************************
469 * ComputeHeight (mbutton)
473 * Returns the ideal height of the menubutton by considering whether the
474 * label is text or image.
478 * mbutton = widget to compute height of
482 * returns the ideal height of mbutton
487 *************************************<->***********************************/
489 static Dimension
ComputeHeight(mbutton
)
490 XwMenuButtonWidget mbutton
;
494 if (mbutton
->menubutton
.labelType
== XwSTRING
)
495 max
= mbutton
->button
.label_height
;
497 if ((mbutton
->menubutton
.labelType
== XwIMAGE
) &&
498 (mbutton
->menubutton
.labelImage
->height
> max
))
499 max
= mbutton
->menubutton
.labelImage
->height
;
501 if (mbutton
->menubutton
.markImage
->height
> max
)
502 max
= mbutton
->menubutton
.markImage
->height
;
504 if (mbutton
->menubutton
.cascadeImage
->height
> max
)
505 max
= mbutton
->menubutton
.cascadeImage
->height
;
507 return (max
+ 2 * mbutton
->button
.internal_height
+
508 2 * mbutton
->primitive
.highlight_thickness
);
512 /*************************************<->*************************************
518 * Computes the values for mark_y, label_y and cascade_y.
522 * mbutton = menubutton to compute and set values for
530 *************************************<->***********************************/
532 static void ComputeVertical (mbutton
)
533 XwMenuButtonWidget mbutton
;
537 string_y
= (mbutton
->core
.height
- mbutton
->button
.label_height
)/2 +
538 mbutton
->button
.font
->max_bounds
.ascent
;
540 if (mbutton
->menubutton
.labelType
== XwSTRING
)
541 mbutton
->button
.label_y
= string_y
;
543 else if (mbutton
->menubutton
.labelImage
)
544 mbutton
->button
.label_y
= (mbutton
->core
.height
-
545 mbutton
->menubutton
.labelImage
->height
) / 2;
547 mbutton
->menubutton
.mark_y
= (mbutton
->core
.height
-
548 mbutton
->menubutton
.markImage
->height
)/2;
550 mbutton
->menubutton
.cascade_y
= (mbutton
->core
.height
-
551 mbutton
->menubutton
.cascadeImage
->height
)/2;
555 /*************************************<->*************************************
557 * SetUnderline (mbutton)
561 * Set the underline parameters underline_width and underline_y.
565 * mbutton = menubutton
573 * XGetFontProperty ()
575 *************************************<->***********************************/
577 static void SetUnderline (mbutton
)
578 XwMenuButtonWidget mbutton
;
582 if ((!mbutton
->menubutton
.mgrOverrideMnemonic
) &&
583 (mbutton
->menubutton
.mnemonic
))
585 mbutton
->menubutton
.mnemonicMatch
= FALSE
;
586 temp
= XwStrlen (mbutton
->button
.label
);
588 for (i
= 0; i
< temp
;)
591 if (XHPIs16bitCharacter (mbutton
->button
.font
->fid
,
592 mbutton
->button
.label
[i
],
593 mbutton
->button
.label
[i
+1]) == NULL
)
596 if (*mbutton
->menubutton
.mnemonic
==
597 (char) mbutton
->button
.label
[i
])
601 mbutton
->menubutton
.mnemonicMatch
= TRUE
;
602 mbutton
->menubutton
.underline_width
=
603 XTextWidth(mbutton
->button
.font
, mbutton
->button
.label
+i
, 1);
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
;
610 if (XGetFontProperty(mbutton
->button
.font
, XA_UNDERLINE_POSITION
,
612 mbutton
->menubutton
.underline_y
=
613 mbutton
->button
.font
->descent
+1;
615 mbutton
->menubutton
.underline_y
= (Dimension
) bval
;
617 mbutton
->menubutton
.underline_y
+= mbutton
->button
.label_y
;
630 mbutton
->menubutton
.mnemonicMatch
= FALSE
;
633 /*************************************<->*************************************
643 * mbutton = menubutton
652 *************************************<->***********************************/
654 static void GetGC (mbutton
)
655 XwMenuButtonWidget mbutton
;
659 unsigned long dostipple
= 0;
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
;
670 values
.foreground
= mbutton
->primitive
.foreground
;
671 values
.background
= mbutton
->core
.background_pixel
;
673 mbutton
->menubutton
.defPixmap_GC
=
674 XtGetGC ((Widget
) mbutton
,
675 GCFunction
| GCPlaneMask
| GCSubwindowMode
|
676 GCGraphicsExposures
| GCClipXOrigin
| GCClipYOrigin
|
677 GCClipMask
| GCForeground
| GCBackground
,
680 values
.foreground
= mbutton
->core
.background_pixel
;
681 values
.background
= mbutton
->primitive
.foreground
;
683 mbutton
->menubutton
.invertPixmap_GC
=
684 XtGetGC ((Widget
) mbutton
,
685 GCFunction
| GCPlaneMask
| GCSubwindowMode
|
686 GCGraphicsExposures
| GCClipXOrigin
| GCClipYOrigin
|
687 GCClipMask
| GCForeground
| GCBackground
,
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
;
698 values
.foreground
= mbutton
->menubutton
.rectColor
;
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
);
708 /*************************************<->*************************************
717 * mbutton = menubutton
725 *************************************<->***********************************/
727 static void GetDefImages (mbutton
)
728 XwMenuButtonWidget mbutton
;
730 static unsigned char defMarkData
[] =
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,
738 static unsigned char defCascadeData
[] =
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
746 mbutton
->menubutton
.defMarkImage
=
747 XCreateImage (XtDisplay(mbutton
), CopyFromParent
, 1, XYBitmap
, 0,
748 defMarkData
, 16, 16, 8, 2);
750 mbutton
->menubutton
.defMarkImage
->byte_order
= MSBFirst
;
751 mbutton
->menubutton
.defMarkImage
->bitmap_bit_order
= LSBFirst
;
752 mbutton
->menubutton
.defMarkImage
->bitmap_unit
= 8;
755 mbutton
->menubutton
.defCascadeImage
=
756 XCreateImage (XtDisplay(mbutton
), CopyFromParent
, 1, XYBitmap
, 0,
757 defCascadeData
, 16, 16, 8, 2);
759 mbutton
->menubutton
.defCascadeImage
->byte_order
= MSBFirst
;
760 mbutton
->menubutton
.defCascadeImage
->bitmap_bit_order
= LSBFirst
;
761 mbutton
->menubutton
.defCascadeImage
->bitmap_unit
= 8;
764 /*************************************<->*************************************
773 * mbutton = menubutton
781 *************************************<->***********************************/
783 static void CreatePixmap (mbutton
, image
, pix
, invertedPix
)
784 XwMenuButtonWidget mbutton
;
787 Pixmap
* invertedPix
;
789 if (*pix
!= (Pixmap
)NULL
)
790 XFreePixmap (XtDisplay(mbutton
), *pix
);
792 if (*invertedPix
!= (Pixmap
)NULL
)
793 XFreePixmap (XtDisplay(mbutton
), *invertedPix
);
797 *pix
= XCreatePixmap (XtDisplay(mbutton
),
798 RootWindowOfScreen(XtScreen(mbutton
)),
799 image
->width
, image
->height
,
800 DefaultDepthOfScreen(XtScreen(mbutton
)));
802 XPutImage (XtDisplay(mbutton
), *pix
, mbutton
->menubutton
.defPixmap_GC
,
803 image
, 0, 0, 0, 0, image
->width
, image
->height
);
805 if (image
->format
== XYBitmap
)
807 *invertedPix
= XCreatePixmap (XtDisplay(mbutton
),
808 RootWindowOfScreen(XtScreen(mbutton
)),
809 image
->width
, image
->height
,
810 DefaultDepthOfScreen(XtScreen(mbutton
)));
812 XPutImage (XtDisplay(mbutton
), *invertedPix
,
813 mbutton
->menubutton
.invertPixmap_GC
,
814 image
, 0, 0, 0, 0, image
->width
, image
->height
);
821 *invertedPix
= (Pixmap
)NULL
;
825 /*************************************<->*************************************
831 * NOTE!!! This should be eventually replaced by a QueryProc.
835 * w = menubutton widget
844 *************************************<->***********************************/
846 static void IdealWidth (w
, width
)
850 XwMenuButtonWidget mbutton
= (XwMenuButtonWidget
) w
;
852 *width
= 2 * mbutton
->primitive
.highlight_thickness
+
853 2 * (XwMENUBTNPAD
+ mbutton
->button
.internal_width
) +
854 XwMARKWIDTH
+ XwCASCADEWIDTH
;
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
;
862 /*************************************<->*************************************
864 * Initialize (request, new)
868 * This is the menubutton instance initialize procedure.
873 * request = original instance record;
875 * new = instance record with modifications induced by
876 * other initialize routines, changes are made to this
879 * args = argument list specified in XtCreateWidget;
881 * num_args = argument count;
889 *************************************<->***********************************/
891 static void Initialize (request
, new)
897 XwMenuButtonWidget mbutton
= (XwMenuButtonWidget
) new;
899 /* Augment our translations to include the traversal actions */
900 XtAugmentTranslations ((Widget
)mbutton
,
901 XwprimitiveClassRec
.primitive_class
.translations
);
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.
908 mbutton
->primitive
.traversal_type
= XwHIGHLIGHT_OFF
;
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
;
919 GetDefImages(mbutton
);
923 * If the menuMgr field has not been set up, check if in a menu system
924 * (menu manager as ancestor).
926 if (mbutton
->menubutton
.menuMgr
== NULL
)
928 if ((XtIsSubclass (XtParent (mbutton
), XwmenupaneWidgetClass
)) &&
929 (XtIsSubclass (XtParent (XtParent (mbutton
)), shellWidgetClass
)) &&
930 (XtIsSubclass (XtParent (XtParent (XtParent (mbutton
))),
931 XwmenumgrWidgetClass
)))
933 mbutton
->menubutton
.menuMgr
=
934 (Widget
) XtParent (XtParent (XtParent(mbutton
)));
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.
942 if ((mbutton
->menubutton
.accelerator
) &&
943 (_XwMapKeyEvent (mbutton
->menubutton
.accelerator
,
944 &mbutton
->menubutton
.accelEventType
,
946 &mbutton
->menubutton
.accelModifiers
)))
948 mbutton
->menubutton
.accelDetail
= XKeysymToKeycode (XtDisplay(mbutton
),
950 mbutton
->menubutton
.accelerator
=
951 strcpy(XtMalloc((unsigned)(XwStrlen(mbutton
->menubutton
.accelerator
)+1)),
952 mbutton
->menubutton
.accelerator
);
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;
964 if (mbutton
->menubutton
.hint
)
965 mbutton
->menubutton
.hint
=
966 strcpy(XtMalloc((unsigned)(XwStrlen(mbutton
->menubutton
.hint
)+1)),
967 mbutton
->menubutton
.hint
);
970 * malloc space for mnemonic. Only take 1st character & null
972 if ((mbutton
->menubutton
.mnemonic
) &&
973 (*(mbutton
->menubutton
.mnemonic
) != '\0'))
975 char mne
= mbutton
->menubutton
.mnemonic
[0];
977 mbutton
->menubutton
.mnemonic
= (String
) XtMalloc(2);
978 mbutton
->menubutton
.mnemonic
[0] = mne
;
979 mbutton
->menubutton
.mnemonic
[1] = '\0';
982 if (mbutton
->menubutton
.mnemonic
)
983 XtWarning ("MenuButton: Invalid mnemonic; disabling feature");
985 if (mbutton
->menubutton
.labelImage
)
986 CreatePixmap(mbutton
, mbutton
->menubutton
.labelImage
,
987 &mbutton
->menubutton
.labelPixmap
,
988 &mbutton
->menubutton
.invertLabelPixmap
);
990 if (!mbutton
->menubutton
.markImage
)
991 mbutton
->menubutton
.markImage
= mbutton
->menubutton
.defMarkImage
;
993 CreatePixmap(mbutton
, mbutton
->menubutton
.markImage
,
994 &mbutton
->menubutton
.markPixmap
,
995 &mbutton
->menubutton
.invertMarkPixmap
);
997 if (!mbutton
->menubutton
.cascadeImage
)
998 mbutton
->menubutton
.cascadeImage
= mbutton
->menubutton
.defCascadeImage
;
1000 CreatePixmap(mbutton
, mbutton
->menubutton
.cascadeImage
,
1001 &mbutton
->menubutton
.cascadePixmap
,
1002 &mbutton
->menubutton
.invertCascadePixmap
);
1004 if (request
->core
.height
<= 0)
1005 mbutton
->core
.height
= ComputeHeight(mbutton
);
1007 ComputeVertical(mbutton
);
1008 SetUnderline(mbutton
);
1010 if (request
->core
.width
<= 0)
1011 IdealWidth(mbutton
, &mbutton
->core
.width
);
1014 /*************************************<->*************************************
1030 *************************************<->***********************************/
1032 static void Destroy (mbutton
)
1033 XwMenuButtonWidget mbutton
;
1035 if (mbutton
->menubutton
.accelerator
)
1036 XtFree (mbutton
->menubutton
.accelerator
);
1038 XtDestroyGC (mbutton
->menubutton
.defPixmap_GC
);
1039 XtDestroyGC (mbutton
->menubutton
.inverted_GC
);
1040 XtDestroyGC (mbutton
->menubutton
.invertPixmap_GC
);
1041 XtDestroyGC (mbutton
->menubutton
.rect_GC
);
1043 mbutton
->menubutton
.defMarkImage
->data
= NULL
;
1044 XDestroyImage (mbutton
->menubutton
.defMarkImage
);
1045 mbutton
->menubutton
.defCascadeImage
->data
= NULL
;
1046 XDestroyImage (mbutton
->menubutton
.defCascadeImage
);
1048 XtRemoveAllCallbacks ((Widget
)mbutton
, XtNcascadeSelect
);
1049 XtRemoveAllCallbacks ((Widget
)mbutton
, XtNcascadeUnselect
);
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
);
1057 /*************************************<->*************************************
1063 * Creates the window for this menubutton instance. Sets bit gravity
1064 * so that on resize the menubutton is repainted.
1069 * w = widget to be realized.
1071 * valueMask = contains event mask for this window/widget.
1073 * attributes = window attributes for this window/widget.
1081 *************************************<->***********************************/
1083 static void Realize(w
, p_valueMask
, attributes
)
1085 XtValueMask
* p_valueMask
;
1086 XSetWindowAttributes
* attributes
;
1088 XwMenuButtonWidget mbutton
= (XwMenuButtonWidget
) w
;
1090 XtValueMask valueMask
= *p_valueMask
;
1091 valueMask
|= CWBitGravity
;
1092 attributes
->bit_gravity
= ForgetGravity
;
1095 XtCreateWindow ((Widget
)mbutton
, InputOutput
, (Visual
*) CopyFromParent
,
1096 valueMask
, attributes
);
1098 _XwRegisterName (mbutton
);
1101 /*************************************<->*************************************
1103 * Select (w, event) PRIVATE
1107 * Mark menubutton as selected, (i.e., draw it as active)
1108 * Generate the correct callbacks.
1113 * w = widget instance that was selected.
1114 * event = event record
1122 *************************************<->***********************************/
1124 static void Select(w
,event
)
1129 XwMenuButtonWidget mbutton
= (XwMenuButtonWidget
) w
;
1131 /* Don't do anything if its not sensitive. */
1133 if (XtIsSensitive((Widget
)mbutton
))
1136 * if there is a menu manager, call the process select routine to
1137 * determine if the event is valid for the menu system.
1139 if (mbutton
->menubutton
.menuMgr
)
1141 if ((*(((XwMenuMgrWidgetClass
) XtClass(mbutton
->menubutton
.menuMgr
))->
1142 menu_mgr_class
.processSelect
))
1143 (mbutton
->menubutton
.menuMgr
, mbutton
, event
) == FALSE
)
1149 XtCallCallbacks ((Widget
)mbutton
, XtNselect
, NULL
);
1153 /*************************************<->*************************************
1155 * DrawLabelMarkCascade (mbutton)
1169 *************************************<->***********************************/
1171 static void DrawLabelMarkCascade (mbutton
)
1172 XwMenuButtonWidget mbutton
;
1174 Dimension labelStarts
;
1178 if (mbutton
->menubutton
.inverted
)
1179 theGC
= mbutton
->button
.inverse_GC
;
1181 theGC
= mbutton
->button
.normal_GC
;
1184 if (mbutton
->menubutton
.noPad
== True
)
1185 labelStarts
= mbutton
->primitive
.highlight_thickness
+
1186 mbutton
->button
.internal_width
;
1188 labelStarts
= mbutton
->primitive
.highlight_thickness
+
1189 mbutton
->button
.internal_width
+ XwMENUBTNPAD
+ XwMARKWIDTH
;
1191 * Draw the label with its underline if needed.
1193 if (mbutton
->menubutton
.labelType
== XwSTRING
)
1196 XtDisplay(mbutton
), XtWindow(mbutton
), theGC
,
1197 labelStarts
, mbutton
->button
.label_y
,
1198 mbutton
->button
.label
, (int) mbutton
->button
.label_len
);
1200 if ((!mbutton
->menubutton
.mgrOverrideMnemonic
) &&
1201 (mbutton
->menubutton
.mnemonicMatch
))
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
);
1210 else if (mbutton
->menubutton
.labelType
== XwRECT
)
1212 /* Draw a colored or stippled rectangle with a border around it */
1214 if (mbutton
->menubutton
.noPad
== True
) {
1216 XtDisplay(mbutton
), XtWindow(mbutton
),
1217 mbutton
->menubutton
.rect_GC
,
1218 2, 2, mbutton
->menubutton
.labelImage
->width
- 1,
1219 mbutton
->menubutton
.labelImage
->height
- 1);
1221 XtDisplay(mbutton
), XtWindow(mbutton
), theGC
,
1222 2, 2, mbutton
->menubutton
.labelImage
->width
- 1,
1223 mbutton
->menubutton
.labelImage
->height
- 1);
1227 XtDisplay(mbutton
), XtWindow(mbutton
),
1228 mbutton
->menubutton
.rect_GC
,
1229 XwMARKWIDTH
+ 3, 3, mbutton
->core
.width
- XwMARKWIDTH
- 6,
1230 mbutton
->core
.height
- 6);
1232 XtDisplay(mbutton
), XtWindow(mbutton
), theGC
,
1233 XwMARKWIDTH
+ 3, 3, mbutton
->core
.width
- XwMARKWIDTH
- 6,
1234 mbutton
->core
.height
- 6);
1239 if ((mbutton
->menubutton
.inverted
) &&
1240 (mbutton
->menubutton
.invertLabelPixmap
))
1241 thePixmap
= mbutton
->menubutton
.invertLabelPixmap
;
1243 thePixmap
= mbutton
->menubutton
.labelPixmap
;
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
);
1253 * If the mark is set, display the mark.
1255 if (mbutton
->menubutton
.setMark
)
1257 if ((mbutton
->menubutton
.inverted
) &&
1258 (mbutton
->menubutton
.invertMarkPixmap
))
1259 thePixmap
= mbutton
->menubutton
.invertMarkPixmap
;
1261 thePixmap
= mbutton
->menubutton
.markPixmap
;
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
);
1273 * If the cascade is set, display it.
1275 if (mbutton
->menubutton
.cascadeOn
)
1277 if ((mbutton
->menubutton
.inverted
) &&
1278 (mbutton
->menubutton
.invertCascadePixmap
))
1279 thePixmap
= mbutton
->menubutton
.invertCascadePixmap
;
1281 thePixmap
= mbutton
->menubutton
.cascadePixmap
;
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
);
1294 /*************************************<->*************************************
1296 * Inverted (mbutton)
1310 * DrawLabelMarkCascade
1312 *************************************<->***********************************/
1314 static void Inverted (mw
)
1315 XwMenuButtonWidget mw
;
1318 mw
-> menubutton
.inverted
= TRUE
;
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
);
1333 /*************************************<->*************************************
1335 * NonInverted (mbutton)
1349 * DrawLabelMarkCascade
1351 *************************************<->***********************************/
1353 static void NonInverted (mbutton
)
1354 XwMenuButtonWidget mbutton
;
1357 mbutton
->menubutton
.inverted
= FALSE
;
1359 XClearWindow (XtDisplay(mbutton
), XtWindow(mbutton
));
1360 DrawLabelMarkCascade (mbutton
);
1365 /*************************************<->*************************************
1367 * Highlight(mbutton)
1383 *************************************<->***********************************/
1385 static void Highlight (mbutton
)
1386 XwMenuButtonWidget mbutton
;
1389 if (mbutton->primitive.traversal_type == XwHIGHLIGHT_TRAVERSAL)
1390 _XwHighlightBorder(mbutton);
1396 /*************************************<->*************************************
1398 * Unhighlight (mbutton)
1414 *************************************<->***********************************/
1416 static void Unhighlight (mbutton
)
1417 XwMenuButtonWidget mbutton
;
1420 if (mbutton->primitive.traversal_type == XwHIGHLIGHT_TRAVERSAL)
1421 _XwUnhighlightBorder(mbutton);
1424 NonInverted (mbutton
);
1425 mbutton
->menubutton
.cascadeEnabled
= FALSE
;
1428 /*************************************<->*************************************
1430 * Enter (w, event) PRIVATE
1437 * w = widget instance that was selected.
1438 * event = event record
1448 *************************************<->***********************************/
1450 static void Enter(w
,event
)
1454 XwMenuButtonWidget mbutton
= (XwMenuButtonWidget
)w
;
1457 printf ("Enter %s\n", w
->core
.name
);
1459 if ((mbutton
->menubutton
.menuMgr
== NULL
) ||
1460 ((*(((XwMenuMgrWidgetClass
)
1461 XtClass (mbutton
->menubutton
.menuMgr
))->menu_mgr_class
.validEvent
))
1462 (mbutton
->menubutton
.menuMgr
, mbutton
, event
)))
1465 * Check on cascade indicator
1470 * if (mbutton->primitive.traversal_type != XwHIGHLIGHT_TRAVERSAL)
1475 /* to-do: if no hintProc is specified, should generate a hint tag */
1477 if ((mbutton
->menubutton
.hint
!= NULL
) &&
1478 (mbutton
->menubutton
.hintProc
!= NULL
)) {
1479 mbutton
->menubutton
.hintProc(mbutton
->menubutton
.hint
);
1483 /*************************************<->*************************************
1485 * EnterParentsWindow (menupane, mbutton,event)
1499 *************************************<->***********************************/
1501 static void EnterParentsWindow (menupane
, mbutton
, event
)
1503 XwMenuButtonWidget mbutton
;
1506 Boolean remainHighlighted
;
1507 XwunselectParams params
;
1509 XEnterWindowEvent
* entEvent
= (XEnterWindowEvent
*) event
;
1512 printf ("EnterParents %s %s ", menupane
->core
.name
, mbutton
->core
.name
);
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.
1520 if ((entEvent
->y
< mbutton
->core
.y
) ||
1521 (entEvent
->y
> mbutton
->core
.y
+ mbutton
->core
.height
+
1522 2 * mbutton
->core
.border_width
))
1524 params
.rootX
= entEvent
->x_root
;
1525 params
.rootY
= entEvent
->y_root
;
1526 params
.remainHighlighted
= FALSE
;
1529 printf ("rootX %d rootY %d\n", params
.rootX
, params
.rootY
);
1530 printf ("disabled\n");
1533 XtCallCallbacks ((Widget
)mbutton
, XtNcascadeUnselect
, ¶ms
);
1534 mbutton
->menubutton
.cascadeEnabled
= params
.remainHighlighted
;
1535 if (mbutton
->menubutton
.cascadeEnabled
== FALSE
)
1536 Unhighlight (mbutton
);
1539 * Moved (mbutton, event);
1546 XtRemoveEventHandler (menupane
, EnterWindowMask
, FALSE
,
1547 (XtEventHandler
)EnterParentsWindow
, mbutton
);
1550 /*************************************<->*************************************
1552 * Leave (w, event) PRIVATE
1568 *************************************<->***********************************/
1570 static void Leave(w
,event
)
1575 XwunselectParams params
;
1576 XwMenuButtonWidget mbutton
= (XwMenuButtonWidget
)w
;
1577 XLeaveWindowEvent
* lEvent
= (XLeaveWindowEvent
*) event
;
1579 params
.rootX
= lEvent
->x_root
;
1580 params
.rootY
= lEvent
->y_root
;
1583 if ((mbutton
->menubutton
.menuMgr
== NULL
) ||
1584 ((*(((XwMenuMgrWidgetClass
)
1585 XtClass (mbutton
->menubutton
.menuMgr
))->menu_mgr_class
.validEvent
))
1586 (mbutton
->menubutton
.menuMgr
, mbutton
, event
)))
1588 if (mbutton
->menubutton
.cascadeEnabled
)
1590 params
.remainHighlighted
= FALSE
;
1591 XtCallCallbacks ((Widget
)mbutton
, XtNcascadeUnselect
, ¶ms
);
1592 mbutton
->menubutton
.cascadeEnabled
= params
.remainHighlighted
;
1594 if (mbutton
->menubutton
.cascadeEnabled
)
1596 XtAddEventHandler (XtParent(mbutton
), EnterWindowMask
, FALSE
,
1597 (XtEventHandler
)EnterParentsWindow
, mbutton
);
1602 if (mbutton
->menubutton
.inverted
)
1603 NonInverted(mbutton
);
1606 if ((mbutton
->menubutton
.hint
!= NULL
) &&
1607 (mbutton
->menubutton
.hintProc
!= NULL
)) {
1608 mbutton
->menubutton
.hintProc("");
1612 /*************************************<->*************************************
1630 *************************************<->***********************************/
1632 static void Moved (w
,event
)
1637 XwMenuButtonWidget mbutton
= (XwMenuButtonWidget
)w
;
1639 int xPosition
, yPosition
;
1643 XwunselectParams params
;
1645 XButtonPressedEvent
* buttonEvent
= (XButtonPressedEvent
*) event
;
1648 printf ("Moved %s\n", w
->core
.name
);
1652 * only do this if I have a cascade showing
1654 if ((mbutton
->menubutton
.cascadeOn
) &&
1655 (mbutton
->primitive
.traversal_type
== XwHIGHLIGHT_OFF
))
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
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
))
1668 * check if the event appears to have occurred in the cascade area
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
-
1679 mbutton
->primitive
.highlight_thickness
-
1680 mbutton
->button
.internal_width
)))
1683 * Verify that its really in the cascade area
1685 XQueryPointer (XtDisplay(mbutton
), mbutton
->core
.window
,
1686 &root
, &child
, &xroot
, &yroot
, &xPosition
,
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
))
1699 if (!mbutton
->menubutton
.cascadeEnabled
)
1701 XtCallCallbacks ((Widget
)mbutton
, XtNcascadeSelect
, NULL
);
1703 printf ("enabled\n");
1705 mbutton
->menubutton
.cascadeEnabled
= TRUE
;
1708 else if (mbutton
->menubutton
.cascadeEnabled
)
1710 params
.rootX
= xroot
;
1711 params
.rootY
= yroot
;
1712 params
.remainHighlighted
= FALSE
;
1714 printf ("Moved rootX %d rootY %d\n", params
.rootX
, params
.rootY
);
1716 XtCallCallbacks ((Widget
)mbutton
, XtNcascadeUnselect
, ¶ms
);
1717 mbutton
->menubutton
.cascadeEnabled
= params
.remainHighlighted
;
1724 /*************************************<->*************************************
1726 * Redisplay (w, event)
1730 * Cause the widget, identified by w, to be redisplayed.
1734 * w = widget to be redisplayed;
1735 * event = event structure identifying need for redisplay on this
1745 * _XwHighlightBorder
1746 * _XwUnhighlightBorder
1748 *************************************<->***********************************/
1750 static void Redisplay(w
, event
)
1754 XwMenuButtonWidget mbutton
= (XwMenuButtonWidget
) w
;
1757 * if the highlight state has changed since the last redisplay,
1758 * update the window and set the font GC.
1760 if (mbutton
->menubutton
.inverted
)
1764 NonInverted(mbutton
);
1766 if (mbutton
->primitive
.highlighted
)
1767 _XwHighlightBorder(mbutton
);
1770 if (mbutton
->primitive
.display_highlighted
)
1771 _XwUnhighlightBorder(mbutton
);
1774 /*************************************<->*************************************
1776 * SetValues(urrent, request, new)
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
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;
1798 *************************************<->***********************************/
1800 static Boolean
SetValues (current
, request
, new)
1801 Widget current
, request
, new;
1803 XtWidgetGeometry reqGeo
;
1804 XtWidgetGeometry replyGeo
;
1805 XwMenuButtonWidget curmbutton
= (XwMenuButtonWidget
) current
;
1806 XwMenuButtonWidget newmbutton
= (XwMenuButtonWidget
) new;
1807 Boolean flag
= FALSE
; /* our return value */
1811 /* We never allow our traversal state to change using SetValues() */
1812 newmbutton
->primitive
.traversal_type
= curmbutton
->primitive
.traversal_type
;
1815 * If the accelerator string changed, malloc space for the string
1816 * and copy it to our space. The old string must be freed.
1819 if (curmbutton
->menubutton
.accelerator
!=
1820 newmbutton
->menubutton
.accelerator
)
1822 if (newmbutton
->menubutton
.accelerator
)
1824 if (_XwMapKeyEvent (newmbutton
->menubutton
.accelerator
,
1825 &newmbutton
->menubutton
.accelEventType
,
1827 &newmbutton
->menubutton
.accelModifiers
)
1830 /* Invalid string; revert to previous one */
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
;
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
);
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
);
1862 if (curmbutton
->menubutton
.accelerator
)
1863 XtFree ((char *) curmbutton
->menubutton
.accelerator
);
1866 else if (curmbutton
->menubutton
.accelerator
)
1868 if (curmbutton
->menubutton
.menuMgr
)
1869 (*(((XwMenuMgrWidgetClass
)
1870 XtClass(curmbutton
->menubutton
.menuMgr
))->
1871 menu_mgr_class
.clearSelectAccelerator
))
1872 (curmbutton
->menubutton
.menuMgr
, (Widget
)curmbutton
);
1874 XtFree ((char *) curmbutton
->menubutton
.accelerator
);
1879 * Determine if the mnemonic changed, verify and malloc space.
1880 * Notify menuMgr of the change.
1883 if (curmbutton
->menubutton
.mnemonic
!= newmbutton
->menubutton
.mnemonic
)
1885 if (newmbutton
->menubutton
.mnemonic
)
1887 if (*(newmbutton
->menubutton
.mnemonic
) == '\0')
1890 ("MenuButton: Invalid mnemonic; using previous setting");
1891 newmbutton
->menubutton
.mnemonic
= curmbutton
->menubutton
.mnemonic
;
1895 char mne
= newmbutton
->menubutton
.mnemonic
[0];
1897 newmbutton
->menubutton
.mnemonic
= (String
)XtMalloc(2);
1898 newmbutton
->menubutton
.mnemonic
[0] = mne
;
1899 newmbutton
->menubutton
.mnemonic
[1] = '\0';
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
);
1908 XtFree (curmbutton
->menubutton
.mnemonic
);
1913 if (newmbutton
->menubutton
.menuMgr
)
1914 (*(((XwMenuMgrWidgetClass
)
1915 XtClass (curmbutton
->menubutton
.menuMgr
))->
1916 menu_mgr_class
.clearSelectMnemonic
))
1917 (curmbutton
->menubutton
.menuMgr
, (Widget
)curmbutton
);
1919 XtFree(curmbutton
->menubutton
.mnemonic
);
1924 * recalculate the underline parameters if mnemonic or font changes
1926 if ((newmbutton
->menubutton
.mnemonic
!= curmbutton
->menubutton
.mnemonic
) ||
1927 (newmbutton
->button
.font
!= curmbutton
->button
.font
))
1929 SetUnderline (newmbutton
);
1935 * If the foreground or background changed, or the color or stipple
1936 * declaration was changed, recreate the GC's
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
))
1948 XtDestroyGC (curmbutton
->menubutton
.defPixmap_GC
);
1949 XtDestroyGC (curmbutton
->menubutton
.invertPixmap_GC
);
1953 * If the GCs are new, or the images are new, create new pixmaps
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
))
1962 if (!newmbutton
->menubutton
.markImage
)
1963 newmbutton
->menubutton
.markImage
=
1964 newmbutton
->menubutton
.defMarkImage
;
1966 CreatePixmap(newmbutton
, newmbutton
->menubutton
.markImage
,
1967 &newmbutton
->menubutton
.markPixmap
,
1968 &newmbutton
->menubutton
.invertMarkPixmap
);
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
))
1979 if (!newmbutton
->menubutton
.cascadeImage
)
1980 newmbutton
->menubutton
.cascadeImage
=
1981 newmbutton
->menubutton
.defCascadeImage
;
1983 CreatePixmap(newmbutton
, newmbutton
->menubutton
.cascadeImage
,
1984 &newmbutton
->menubutton
.cascadePixmap
,
1985 &newmbutton
->menubutton
.invertCascadePixmap
);
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
))
1996 CreatePixmap(newmbutton
, newmbutton
->menubutton
.labelImage
,
1997 &newmbutton
->menubutton
.labelPixmap
,
1998 &newmbutton
->menubutton
.invertLabelPixmap
);
2000 if (newmbutton
->menubutton
.labelType
== XwIMAGE
)
2004 if ((newmbutton
->core
.sensitive
!= curmbutton
->core
.sensitive
) ||
2005 (newmbutton
->core
.ancestor_sensitive
!=
2006 curmbutton
->core
.ancestor_sensitive
))
2008 if (curmbutton
->menubutton
.menuMgr
)
2010 (*(((XwMenuMgrWidgetClass
)
2011 XtClass(curmbutton
->menubutton
.menuMgr
))->
2012 menu_mgr_class
.btnSensitivityChanged
))
2013 (curmbutton
->menubutton
.menuMgr
, (Widget
)newmbutton
);
2018 * fields that change that cause a redraw
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
))
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 *********************************************************************/
2046 /* "noPad" option prevents button from resizing itself 2/24/00 --Tim */
2048 if (curmbutton
->core
.width
== request
->core
.width
&&
2049 curmbutton
->menubutton
.noPad
== False
)
2051 IdealWidth (newmbutton
, &newmbutton
->core
.width
);
2054 else if (request
->core
.width
<= 0)
2056 XtWarning ("MenuButton: Invalid width; using previous setting");
2057 newmbutton
->core
.width
= curmbutton
->core
.width
;
2060 if (curmbutton
->core
.height
== request
->core
.height
&&
2061 curmbutton
->menubutton
.noPad
== False
)
2063 newmbutton
->core
.height
= ComputeHeight(newmbutton
);
2066 else if (request
->core
.height
<= 0)
2068 XtWarning ("MenuButton: Invalid height; using previous setting");
2069 newmbutton
->core
.height
= curmbutton
->core
.height
;
2075 /*************************************<->*************************************
2081 * A resize event has been generated. Recompute location of button
2086 * w = widget to be resized.
2094 *************************************<->***********************************/
2096 static void Resize(w
)
2100 XwMenuButtonWidget mbutton
= (XwMenuButtonWidget
) w
;
2102 ComputeVertical(mbutton
);
2103 SetUnderline(mbutton
);
2107 /*************************************<->*************************************
2109 * SetTraversalType(w)
2123 *************************************<->***********************************/
2125 static void SetTraversalType (w
, highlight_mode
)
2132 XwMenuButtonWidget mbutton
= (XwMenuButtonWidget
) w
;
2134 mbutton
->primitive
.traversal_type
= highlight_mode
;
2136 if (highlight_mode
== XwHIGHLIGHT_TRAVERSAL
)
2138 XtAugmentTranslations (w
, XwprimitiveClassRec
.primitive_class
.
2140 w
->core
.widget_class
->core_class
.visible_interest
= True
;
2145 /*************************************<->*************************************
2147 * TraverseRight(w, event)
2161 *************************************<->***********************************/
2163 static void TraverseRight (w
, event
)
2165 XwMenuButtonWidget w
;
2170 * Ask the menu manager to traverse to the next menupane, if we
2174 if ((w
->menubutton
.cascadeOn
) && (w
->menubutton
.menuMgr
) &&
2175 (w
->primitive
.I_have_traversal
) && (_XwUniqueEvent (event
)))
2177 (*(((XwMenuMgrWidgetClass
)
2178 XtClass(w
->menubutton
.menuMgr
))->menu_mgr_class
.traverseRight
))
2179 (w
->menubutton
.menuMgr
, event
);
2184 /*************************************<->*************************************
2186 * TraverseLeft(w, event)
2200 *************************************<->***********************************/
2202 static void TraverseLeft (w
, event
)
2204 XwMenuButtonWidget w
;
2209 * Ask the menu manager to traverse to the previous menupane.
2212 if ((w
->menubutton
.menuMgr
) && (_XwUniqueEvent (event
)) &&
2213 (w
->primitive
.I_have_traversal
))
2215 (*(((XwMenuMgrWidgetClass
)
2216 XtClass(w
->menubutton
.menuMgr
))->menu_mgr_class
.traverseLeft
))
2217 (w
->menubutton
.menuMgr
, event
);
2222 /*************************************<->*************************************
2224 * TraverseNext(w, event)
2238 *************************************<->***********************************/
2240 static void TraverseNext (w
, event
)
2242 XwMenuButtonWidget w
;
2247 * Ask the menu manager to traverse to the previous menupane.
2250 if ((w
->menubutton
.menuMgr
) && (_XwUniqueEvent (event
)) &&
2251 (w
->primitive
.I_have_traversal
))
2253 (*(((XwMenuMgrWidgetClass
)
2254 XtClass(w
->menubutton
.menuMgr
))->menu_mgr_class
.traverseNext
))
2255 (w
->menubutton
.menuMgr
, event
);
2260 /*************************************<->*************************************
2262 * TraversePrev(w, event)
2276 *************************************<->***********************************/
2278 static void TraversePrev (w
, event
)
2280 XwMenuButtonWidget w
;
2285 * Ask the menu manager to traverse to the previous menupane.
2288 if ((w
->menubutton
.menuMgr
) && (_XwUniqueEvent (event
)) &&
2289 (w
->primitive
.I_have_traversal
))
2291 (*(((XwMenuMgrWidgetClass
)
2292 XtClass(w
->menubutton
.menuMgr
))->menu_mgr_class
.traversePrev
))
2293 (w
->menubutton
.menuMgr
, event
);
2298 /*************************************<->*************************************
2314 *************************************<->***********************************/
2316 static void TraverseHome (w
, event
)
2318 XwMenuButtonWidget w
;
2323 * Ask the menu manager to traverse to the first menupane.
2326 if ((w
->menubutton
.menuMgr
) && (_XwUniqueEvent (event
)) &&
2327 (w
->primitive
.I_have_traversal
))
2329 (*(((XwMenuMgrWidgetClass
)
2330 XtClass(w
->menubutton
.menuMgr
))->menu_mgr_class
.traverseHome
))
2331 (w
->menubutton
.menuMgr
, event
);
2336 /*************************************<->*************************************
2352 *************************************<->***********************************/
2354 static void TraverseUp (w
, event
)
2356 XwMenuButtonWidget w
;
2361 * Ask the menu manager to traverse up one menu button
2364 if ((w
->menubutton
.menuMgr
) && (_XwUniqueEvent (event
)) &&
2365 (w
->primitive
.I_have_traversal
))
2367 (*(((XwMenuMgrWidgetClass
)
2368 XtClass(w
->menubutton
.menuMgr
))->menu_mgr_class
.traverseUp
))
2369 (w
->menubutton
.menuMgr
, event
);
2374 /*************************************<->*************************************
2390 *************************************<->***********************************/
2392 static void TraverseDown (w
, event
)
2394 XwMenuButtonWidget w
;
2399 * Ask the menu manager to traverse down one menu button
2402 if ((w
->menubutton
.menuMgr
) && (_XwUniqueEvent (event
)) &&
2403 (w
->primitive
.I_have_traversal
))
2405 (*(((XwMenuMgrWidgetClass
)
2406 XtClass(w
->menubutton
.menuMgr
))->menu_mgr_class
.traverseDown
))
2407 (w
->menubutton
.menuMgr
, event
);
2412 /*************************************<->*************************************
2414 * TraverseNextTop(w)
2428 *************************************<->***********************************/
2430 static void TraverseNextTop (w
, event
)
2432 XwMenuButtonWidget w
;
2437 * Ask the menu manager to traverse to the next top level menupane
2440 if ((w
->menubutton
.menuMgr
) && (_XwUniqueEvent (event
)) &&
2441 (w
->primitive
.I_have_traversal
))
2443 (*(((XwMenuMgrWidgetClass
)
2444 XtClass(w
->menubutton
.menuMgr
))->menu_mgr_class
.traverseNextTop
))
2445 (w
->menubutton
.menuMgr
, event
);
2450 /************************************************************************
2453 * Extract the time field from the event structure.
2455 ************************************************************************/
2457 static Time
_XwExtractTime (event
)
2462 if ((event
->type
== ButtonPress
) || (event
->type
== ButtonRelease
))
2463 return (event
->xbutton
.time
);
2465 if ((event
->type
== KeyPress
) || (event
->type
== KeyRelease
))
2466 return (event
->xkey
.time
);
2472 Boolean
_XwUniqueEvent (event
)
2477 static unsigned long serial
= 0;
2478 static Time time
= 0;
2479 static int type
= 0;
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).
2487 if ((time
!= (newTime
= _XwExtractTime (event
))) ||
2488 (type
!= event
->type
) ||
2489 (serial
!= event
->xany
.serial
))
2491 /* Save the fingerprints for the new event */
2493 serial
= event
->xany
.serial
;
2503 /*************************************<->*************************************
2505 * Visibility(parameters)
2509 * xxxxxxxxxxxxxxxxxxxxxxx
2514 * xxxxxxxxxxxx = xxxxxxxxxxxxx
2518 * xxxxxxxxxxxx = xxxxxxxxxxxxx
2523 *************************************<->***********************************/
2525 static void Visibility (widget
, event
)
2532 * Noop; purpose is to prevent Primitive's translation from
2538 /*************************************<->*************************************
2544 * xxxxxxxxxxxxxxxxxxxxxxx
2549 * xxxxxxxxxxxx = xxxxxxxxxxxxx
2553 * xxxxxxxxxxxx = xxxxxxxxxxxxx
2558 *************************************<->***********************************/
2560 static void Unmap (widget
, event
)
2567 * Noop; purpose is to prevent Primitive's translation from