1 /*************************************<+>*************************************
2 *****************************************************************************
8 ** Description: Menu Pane Meta Class Widget
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 *************************************<+>*************************************/
28 #include <X11/IntrinsicP.h>
29 #include <X11/Xutil.h>
30 #include <X11/StringDefs.h>
31 #include <X11/Xatom.h>
35 static void Initialize();
36 static void Destroy();
37 static Boolean
SetValues();
38 static void GetFontGC();
39 static void InsertChild();
40 static void ConstraintInitialize();
41 static void ClassPartInitialize();
42 static void SetTraversalFlag();
45 /****************************************************************
49 ****************************************************************/
51 static XtResource resources
[] = {
52 {XtNfont
, XtCFont
, XtRFontStruct
, sizeof(XFontStruct
*),
53 XtOffset(XwMenuPaneWidget
, menu_pane
.title_font
), XtRString
, "fixed"},
55 {XtNtitleString
, XtCTitleString
, XtRString
, sizeof(caddr_t
),
56 XtOffset(XwMenuPaneWidget
, menu_pane
.title_string
), XtRString
, NULL
},
58 {XtNtitleImage
, XtCTitleImage
, XtRImage
, sizeof(XImage
*),
59 XtOffset(XwMenuPaneWidget
, menu_pane
.titleImage
), XtRImage
, NULL
},
61 {XtNtitleShowing
, XtCTitleShowing
, XtRBoolean
, sizeof(Boolean
),
62 XtOffset(XwMenuPaneWidget
, menu_pane
.title_showing
), XtRString
, "TRUE"},
64 {XtNattachTo
, XtCAttachTo
, XtRString
, sizeof(String
),
65 XtOffset(XwMenuPaneWidget
, menu_pane
.attach_to
), XtRString
, NULL
},
67 {XtNmgrTitleOverride
, XtCTitleOverride
, XtRBoolean
, sizeof(Boolean
),
68 XtOffset(XwMenuPaneWidget
, menu_pane
.title_override
), XtRString
,
71 {XtNtitleType
, XtCTitleType
, XtRTitleType
, sizeof(int),
72 XtOffset(XwMenuPaneWidget
, menu_pane
.title_type
), XtRString
, "string"},
74 {XtNmnemonic
, XtCMnemonic
, XtRString
, sizeof(String
),
75 XtOffset(XwMenuPaneWidget
, menu_pane
.mnemonic
),XtRString
,NULL
},
77 {XtNselect
, XtCCallback
, XtRCallback
, sizeof(caddr_t
),
78 XtOffset(XwMenuPaneWidget
, menu_pane
.select
), XtRPointer
, NULL
}
82 /****************************************************************
84 * Full class record constant
86 ****************************************************************/
88 XwMenuPaneClassRec XwmenupaneClassRec
= {
90 /* core_class fields */
91 /* superclass */ (WidgetClass
) &XwmanagerClassRec
,
92 /* class_name */ "XwMenuPane",
93 /* widget_size */ sizeof(XwMenuPaneRec
),
94 /* class_initialize */ NULL
,
95 /* class_part_init */ ClassPartInitialize
,
96 /* class_inited */ FALSE
,
97 /* initialize */ Initialize
,
98 /* initialize_hook */ NULL
,
102 /* resources */ resources
,
103 /* num_resources */ XtNumber(resources
),
104 /* xrm_class */ NULLQUARK
,
105 /* compress_motion */ TRUE
,
106 /* compress_exposure */ TRUE
,
107 /* compress_enterlv */ TRUE
,
108 /* visible_interest */ FALSE
,
109 /* destroy */ Destroy
,
112 /* set_values */ SetValues
,
113 /* set_values_hook */ NULL
,
114 /* set_values_almost */ XtInheritSetValuesAlmost
,
115 /* get_values_hook */ NULL
,
116 /* accept_focus */ NULL
,
117 /* version */ XtVersion
,
118 /* PRIVATE cb list */ NULL
,
120 /* query_geometry */ NULL
,
121 /* display_accelerator */ XtInheritDisplayAccelerator
,
124 /* composite_class fields */
125 /* geometry_manager */ NULL
,
126 /* change_managed */ NULL
,
127 /* insert_child */ InsertChild
,
128 /* delete_child */ XtInheritDeleteChild
,
131 /* constraint class fields */
132 /* resources */ NULL
,
133 /* num_resources */ 0,
134 /* Constraint_size */ sizeof (Boolean
),
135 /* initialize */ ConstraintInitialize
,
137 /* set_values */ NULL
,
140 /* manager_class fields */
141 /* traversal handler */ NULL
,
142 /* translations */ NULL
,
144 /* menu pane class - none */
145 /* setTraversalFlag */ (XwWBoolProc
) SetTraversalFlag
149 WidgetClass XwmenupaneWidgetClass
= (WidgetClass
)&XwmenupaneClassRec
;
152 /*************************************<->*************************************
154 * ProcedureName (parameters)
158 * xxxxxxxxxxxxxxxxxxxxxxx
163 * xxxxxxxxxxxx = xxxxxxxxxxxxx
167 * xxxxxxxxxxxx = xxxxxxxxxxxxx
172 *************************************<->***********************************/
174 static void ClassPartInitialize (wc
)
176 register XwMenuPaneWidgetClass wc
;
179 if (wc
->constraint_class
.initialize
== XtInheritMenuPaneConstraintInit
)
180 wc
->constraint_class
.initialize
= (XtInitProc
) ClassPartInitialize
;
182 if (wc
->menu_pane_class
.setTraversalFlag
== XtInheritSetTraversalFlagProc
)
183 wc
->menu_pane_class
.setTraversalFlag
= (XwWBoolProc
) SetTraversalFlag
;
187 /*************************************<->*************************************
189 * ProcedureName (parameters)
193 * xxxxxxxxxxxxxxxxxxxxxxx
198 * xxxxxxxxxxxx = xxxxxxxxxxxxx
202 * xxxxxxxxxxxx = xxxxxxxxxxxxx
207 *************************************<->***********************************/
209 static void ConstraintInitialize (request
, new)
215 Boolean
* managed_and_mapped
;
217 managed_and_mapped
= (Boolean
*) new->core
.constraints
;
219 /* Widgets are never managed when they are first created */
220 *managed_and_mapped
= FALSE
;
224 /*************************************<->*************************************
226 * ProcedureName (parameters)
230 * xxxxxxxxxxxxxxxxxxxxxxx
235 * xxxxxxxxxxxx = xxxxxxxxxxxxx
239 * xxxxxxxxxxxx = xxxxxxxxxxxxx
244 *************************************<->***********************************/
246 static void InsertChild (w
)
249 CompositeWidgetClass composite
;
250 Widget parent
, grandparent
, greatgrandparent
;
252 /* Invoke our superclass's insert_child procedure */
253 composite
= (CompositeWidgetClass
)
254 XwmenupaneWidgetClass
->core_class
.superclass
;
256 (*(composite
->composite_class
.insert_child
)) (w
);
258 /* Call menu mgr's AddButton() procedure */
259 if ((parent
= (Widget
) XtParent(w
)) &&
260 (grandparent
= (Widget
) XtParent(parent
)) &&
261 (greatgrandparent
= (Widget
) XtParent(grandparent
)) &&
262 (XtIsSubclass (greatgrandparent
, XwmenumgrWidgetClass
)))
264 (*((XwMenuMgrWidgetClass
)XtClass(greatgrandparent
))->menu_mgr_class
.
265 addButton
) (greatgrandparent
, w
);
270 /*************************************<->*************************************
277 * Initialize the menu_pane fields within the widget's instance structure.
282 * xxxxxxxxxxxx = xxxxxxxxxxxxx
286 * xxxxxxxxxxxx = xxxxxxxxxxxxx
291 *************************************<->***********************************/
293 static void Initialize (request
, new)
294 XwMenuPaneWidget request
, new;
296 Widget parent
, grandparent
;
300 * Always force traversal off for a menupane. We inherit our
301 * traversal setting from our menu manager, and it will take
302 * care of setting us to the correct state.
304 new->manager
.traversal_on
= FALSE
;
306 new->menu_pane
.attachId
= NULL
;
308 /* Call menu mgr's AddPane() procedure */
309 if ((parent
= (Widget
) XtParent(new)) &&
310 (grandparent
= (Widget
) XtParent(parent
)) &&
311 (XtIsSubclass (grandparent
, XwmenumgrWidgetClass
)))
313 (*((XwMenuMgrWidgetClass
)XtClass(grandparent
))->menu_mgr_class
.addPane
)
314 (grandparent
, (Widget
)new);
320 /* Get the GC used to display the title string/image */
323 /* Save a copy of the title string, if present */
324 if (new->menu_pane
.title_string
)
326 new->menu_pane
.title_string
= (String
)
327 strcpy(XtMalloc(XwStrlen(new->menu_pane
.title_string
) + 1),
328 new->menu_pane
.title_string
);
332 /* Set a default title string: the widget name */
333 new->menu_pane
.title_string
= (String
)
334 strcpy(XtMalloc(XwStrlen(new->core
.name
) + 1),
338 /* Save a copy of the accelerator string, if present */
339 if ((new->menu_pane
.mnemonic
) && (*(new->menu_pane
.mnemonic
) != '\0'))
341 /* Valid mnemonic specified */
342 char mne
= new->menu_pane
.mnemonic
[0];
344 new->menu_pane
.mnemonic
= (String
)XtMalloc(2);
345 new->menu_pane
.mnemonic
[0] = mne
;
346 new->menu_pane
.mnemonic
[1] = '\0';
348 /* Register it with the menu manager */
351 (*((XwMenuMgrWidgetClass
)XtClass(grandparent
))->menu_mgr_class
.
352 setPostMnemonic
) (grandparent
, (Widget
)new, new->menu_pane
.mnemonic
);
357 if (new->menu_pane
.mnemonic
)
358 XtWarning ("MenuPane: Invalid mnemonic; disabling feature");
359 new->menu_pane
.mnemonic
= NULL
;
362 /* Save a copy of the attach string, if present */
363 if (new->menu_pane
.attach_to
)
365 new->menu_pane
.attach_to
= (String
)
366 strcpy(XtMalloc(XwStrlen(new->menu_pane
.attach_to
) + 1),
367 new->menu_pane
.attach_to
);
369 /* Call menu mgr's AttachPane() procedure */
372 (*((XwMenuMgrWidgetClass
)XtClass(grandparent
))->menu_mgr_class
.
373 attachPane
) (grandparent
, (Widget
)new, new->menu_pane
.attach_to
);
380 /*************************************<->*************************************
390 * xxxxxxxxxxxx = xxxxxxxxxxxxx
394 * xxxxxxxxxxxx = xxxxxxxxxxxxx
399 *************************************<->***********************************/
401 static Boolean
SetValues (current
, request
, new)
402 XwMenuPaneWidget current
, request
, new;
404 Boolean redrawFlag
= FALSE
;
405 Boolean titleAttributeChange
= FALSE
;
406 Widget parent
, grandparent
;
409 /* We never allow our traversal flag to change using SetValues() */
410 new->manager
.traversal_on
= current
->manager
.traversal_on
;
412 /* Determine if we are being controlled by a menu manager */
413 if (((parent
= (Widget
) XtParent(new)) == NULL
) ||
414 ((grandparent
= (Widget
) XtParent(parent
)) == NULL
) ||
415 (!XtIsSubclass (grandparent
, XwmenumgrWidgetClass
)))
420 if ((new->menu_pane
.title_type
!= XwSTRING
) &&
421 (new->menu_pane
.title_type
!= XwIMAGE
))
423 XtWarning("MenuPane: Invalid title type; using previous setting");
424 new->menu_pane
.title_type
= current
->menu_pane
.title_type
;
427 if ((current
->menu_pane
.title_showing
!= new->menu_pane
.title_showing
) ||
428 (current
->menu_pane
.title_override
!= new->menu_pane
.title_override
))
433 /* Handle the case of a changed title string or image */
435 if (current
->menu_pane
.title_string
!= new->menu_pane
.title_string
)
437 /* Allocate a new buffer to hold the string */
438 if (new->menu_pane
.title_string
)
440 new->menu_pane
.title_string
= (String
)
441 strcpy (XtMalloc (XwStrlen (new->menu_pane
.title_string
) + 1),
442 new->menu_pane
.title_string
);
446 /* Assign a default title: the widget name */
447 new->menu_pane
.title_string
= (String
)
448 strcpy (XtMalloc (XwStrlen (new->core
.name
) + 1),
453 * Free up the buffer holding the old title string.
454 * XtFree() is smart enough to catch a NULL pointer.
456 XtFree (current
->menu_pane
.title_string
);
458 if (new->menu_pane
.title_type
== XwSTRING
)
460 titleAttributeChange
= TRUE
;
462 if (new->menu_pane
.title_showing
)
467 if (current
->menu_pane
.titleImage
!= new->menu_pane
.titleImage
)
470 * Depending upon whether the depth of the title image can change,
471 * we may need to generate a new GC, which will be used by our call
472 * to XPutImage(). However, I don't believe this is the case.
475 if (new->menu_pane
.title_type
== XwIMAGE
)
477 titleAttributeChange
= TRUE
;
479 if (new->menu_pane
.title_showing
)
484 if (current
->menu_pane
.title_type
!= new->menu_pane
.title_type
)
487 titleAttributeChange
= TRUE
;
491 /* Determine if the menu manager needs to attach us elsewhere */
493 if (current
->menu_pane
.attach_to
!= new->menu_pane
.attach_to
)
495 /* Allocate a new buffer to hold the string */
496 if (new->menu_pane
.attach_to
)
498 new->menu_pane
.attach_to
= (String
)
499 strcpy (XtMalloc (XwStrlen (new->menu_pane
.attach_to
) + 1),
500 new->menu_pane
.attach_to
);
503 /* Call menu mgr's DetachPane() procedure */
506 (*((XwMenuMgrWidgetClass
)XtClass(grandparent
))->menu_mgr_class
.
507 detachPane
) (grandparent
, (Widget
)new, current
->menu_pane
.attach_to
);
511 * Free up the buffer holding the old attach string.
512 * XtFree() is smart enough to catch a NULL pointer.
514 XtFree (current
->menu_pane
.attach_to
);
516 /* Call menu mgr's AttachPane() procedure */
519 (*((XwMenuMgrWidgetClass
)XtClass(grandparent
))->menu_mgr_class
.
520 attachPane
) (grandparent
, (Widget
)new, new->menu_pane
.attach_to
);
524 /* Determine if the post mnemonic needs to be changed */
526 if (current
->menu_pane
.mnemonic
!= new->menu_pane
.mnemonic
)
528 if (new->menu_pane
.mnemonic
)
530 if (*(new->menu_pane
.mnemonic
) == '\0')
532 /* Invalid string; revert to previous one */
534 ("MenuPane: Invalid post mnemonic; using previous setting");
535 new->menu_pane
.mnemonic
= current
->menu_pane
.mnemonic
;
539 /* Valid string; remove old mnemonic, and add new one */
540 char mne
= new->menu_pane
.mnemonic
[0];
542 new->menu_pane
.mnemonic
= (String
) XtMalloc(2);
543 new->menu_pane
.mnemonic
[0] = mne
;
544 new->menu_pane
.mnemonic
[1] = '\0';
546 if (grandparent
&& current
->menu_pane
.mnemonic
)
548 (*((XwMenuMgrWidgetClass
)XtClass(grandparent
))->menu_mgr_class
.
549 clearPostMnemonic
) (grandparent
, (Widget
)current
);
554 (*((XwMenuMgrWidgetClass
)XtClass(grandparent
))->menu_mgr_class
.
555 setPostMnemonic
) (grandparent
, (Widget
)new,
556 new->menu_pane
.mnemonic
);
558 XtFree (current
->menu_pane
.mnemonic
);
563 /* Remove old accelerator */
564 if (grandparent
&& current
->menu_pane
.mnemonic
)
566 (*((XwMenuMgrWidgetClass
)XtClass(grandparent
))->menu_mgr_class
.
567 clearPostMnemonic
) (grandparent
, (Widget
)current
);
570 new->menu_pane
.mnemonic
= NULL
;
572 XtFree(current
->menu_pane
.mnemonic
);
577 /* Force a redraw and get a new GC if the font attributes change */
579 if ((current
->manager
.foreground
!= new->manager
.foreground
) ||
580 (current
->menu_pane
.title_font
->fid
!= new->menu_pane
.title_font
->fid
))
582 XtDestroyGC (current
->menu_pane
.titleGC
);
585 titleAttributeChange
= TRUE
;
588 if ((current
->core
.background_pixel
!= new->core
.background_pixel
) ||
589 (current
->manager
.background_tile
!= new->manager
.background_tile
))
591 titleAttributeChange
= TRUE
;
594 if (((new->core
.sensitive
!= current
->core
.sensitive
) ||
595 (new->core
.ancestor_sensitive
!= current
->core
.ancestor_sensitive
)) &&
598 /* Call menu mgr's paneSensitivityChanged() procedure */
599 (*((XwMenuMgrWidgetClass
)XtClass(grandparent
))->menu_mgr_class
.
600 paneSensitivityChanged
) (grandparent
, (Widget
)new);
603 if (titleAttributeChange
&& grandparent
)
605 /* Call menu mgr's SetTitleAttributes() procedure */
606 (*((XwMenuMgrWidgetClass
)XtClass(grandparent
))->menu_mgr_class
.
607 setTitleAttributes
) (grandparent
, (Widget
)new);
615 /*************************************<->*************************************
625 * xxxxxxxxxxxx = xxxxxxxxxxxxx
629 * xxxxxxxxxxxx = xxxxxxxxxxxxx
634 *************************************<->***********************************/
636 static void GetFontGC (mw
)
643 values
.foreground
= mw
->manager
.foreground
;
644 values
.background
= mw
->core
.background_pixel
;
645 values
.font
= mw
->menu_pane
.title_font
->fid
;
646 values
.line_width
= 1;
647 values
.line_style
= LineSolid
;
648 values
.function
= GXcopy
;
649 values
.plane_mask
= AllPlanes
;
650 values
.subwindow_mode
= ClipByChildren
;
651 values
.clip_x_origin
= 0;
652 values
.clip_y_origin
= 0;
653 values
.clip_mask
= None
;
655 mw
->menu_pane
.titleGC
= XtGetGC ((Widget
)mw
, GCForeground
| GCFont
|
656 GCFunction
| GCLineWidth
| GCLineStyle
|
657 GCBackground
| GCPlaneMask
| GCSubwindowMode
|
658 GCClipXOrigin
| GCClipYOrigin
| GCClipMask
,
663 /*************************************<->*************************************
673 * xxxxxxxxxxxx = xxxxxxxxxxxxx
677 * xxxxxxxxxxxx = xxxxxxxxxxxxx
682 *************************************<->***********************************/
684 static void Destroy (mw
)
689 /* Free up our resources */
691 if (mw
->menu_pane
.title_string
)
692 XtFree (mw
->menu_pane
.title_string
);
694 if (mw
->menu_pane
.attach_to
)
695 XtFree (mw
->menu_pane
.attach_to
);
697 if (mw
->menu_pane
.mnemonic
)
698 XtFree (mw
->menu_pane
.mnemonic
);
700 XtDestroyGC (mw
->menu_pane
.titleGC
);
702 XtRemoveCallbacks ((Widget
)mw
, XtNselect
, mw
->menu_pane
.select
);
706 /*************************************<->*************************************
708 * _XwSetMappedManagedChildrenList (parameters)
712 * MenuPane widgets are only interested in using their children
713 * which are both managed and mapped_when_managed, during layout
714 * calculations. This global routine traverses the list of
715 * children for the specified manager widget, and constructs a
716 * parallel list of only those children meeting the above criteria.
721 * xxxxxxxxxxxx = xxxxxxxxxxxxx
725 * xxxxxxxxxxxx = xxxxxxxxxxxxx
730 *************************************<->***********************************/
732 void _XwSetMappedManagedChildrenList (mw
)
739 mw
->manager
.num_managed_children
= 0;
741 for (i
= 0; i
< mw
->composite
.num_children
; i
++)
743 if ((mw
->composite
.children
[i
]->core
.managed
) &&
744 (mw
->composite
.children
[i
]->core
.mapped_when_managed
))
747 if ((mw
->manager
.num_managed_children
+ 1) >
748 mw
->manager
.num_slots
)
751 mw
->manager
.num_slots
+= XwBLOCK
;
752 mw
->manager
.managed_children
= (WidgetList
)
753 XtRealloc ((caddr_t
)mw
->manager
.managed_children
,
754 (mw
->manager
.num_slots
* sizeof(Widget
)));
757 mw
->manager
.managed_children
[mw
->manager
.num_managed_children
++] =
758 mw
->composite
.children
[i
];
763 * In case this has been called during a SetValues on the pane,
764 * we want to make sure that both the new and old widgets get
767 ((XwManagerWidget
)mw
->core
.self
)->manager
.num_managed_children
=
768 mw
->manager
.num_managed_children
;
769 ((XwManagerWidget
)mw
->core
.self
)->manager
.managed_children
=
770 mw
->manager
.managed_children
;
774 /*************************************<->*************************************
776 * SetTraversalFlag(parameters)
780 * xxxxxxxxxxxxxxxxxxxxxxx
785 * xxxxxxxxxxxx = xxxxxxxxxxxxx
789 * xxxxxxxxxxxx = xxxxxxxxxxxxx
794 *************************************<->***********************************/
796 static void SetTraversalFlag (w
, enableFlag
)
802 w
->manager
.traversal_on
= enableFlag
;
804 if (enableFlag
== True
)
806 XtAugmentTranslations ((Widget
)w
, XwmanagerClassRec
.manager_class
.
808 w
->core
.widget_class
->core_class
.visible_interest
= True
;
813 /*************************************<->*************************************
815 * _XwAllAttachesAreSensitive(parameters)
819 * This functions verifies that the path from a menubutton back upto
820 * the top level menupane has no insensitive widgets (panes or buttons)
826 * xxxxxxxxxxxx = xxxxxxxxxxxxx
830 * xxxxxxxxxxxx = xxxxxxxxxxxxx
835 *************************************<->***********************************/
837 Boolean
_XwAllAttachesAreSensitive (menuBtn
)
842 XwMenuPaneWidget parent
;
844 while (menuBtn
!= NULL
)
846 parent
= (XwMenuPaneWidget
)XtParent(menuBtn
);
848 if (!XtIsSensitive((Widget
)parent
) || !XtIsSensitive(menuBtn
))
851 menuBtn
= (Widget
) parent
->menu_pane
.attachId
;