One more check on valid display which is known to be in the startup
[xcircuit.git] / Xw / Cascade.c
blobb84ec01afcc7faa4dfb98ae5a9aa7b84095a8b4c
1 /*************************************<+>*************************************
2 *****************************************************************************
3 **
4 ** File: Cascade.c
5 **
6 ** Project: X Widgets
7 **
8 ** Description: Code and class record for Cascade widget
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 *************************************<+>*************************************/
28 #include <X11/IntrinsicP.h>
29 #include <X11/Xutil.h>
30 #include <X11/StringDefs.h>
31 #include <X11/Xatom.h>
32 #include <X11/Shell.h>
33 #include <Xw/Xw.h>
34 #include <Xw/XwP.h>
35 #include <Xw/CascadeP.h>
36 #include <Xw/Cascade.h>
37 #include <Xw/MenuBtnP.h>
38 #include <Xw/MenuBtn.h>
39 #include <ctype.h>
41 static void Initialize();
42 static void Realize();
43 static void Resize();
44 static void Redisplay();
45 static void InsertChild();
46 static void Select();
47 static void Leave();
48 static Boolean SetValues();
49 static XtGeometryResult GeometryManager();
50 static void ChangeManaged();
51 static void GetFontGC();
52 static void SetTitleAttributes();
53 static void Visibility();
54 static void Unmap();
56 /* The following are used for layout spacing */
58 #define PADDING_TO_LEFT 2
59 #define PADDING_TO_RIGHT 2
60 #define PADDING_FROM_ABOVE 2
61 #define PADDING_FROM_BELOW PADDING_FROM_ABOVE
62 #define PADDING_FOR_UNDERLINE 0 /* No longer used */
63 #define DOUBLE_LINES 4
66 /****************************************************************
68 * Default translation table for class: MenuPane manager
70 ****************************************************************/
72 static char defaultTranslations[] =
73 "<Btn1Down>: select()\n\
74 <Visible>: visible()\n\
75 <Unmap>: unmap()\n\
76 <LeaveWindow>: leave()";
79 /****************************************************************
81 * Action list for class: MenuPane manager
83 ****************************************************************/
85 static XtActionsRec actionsList[] = {
86 {"select", (XtActionProc) Select},
87 {"visible", (XtActionProc) Visibility},
88 {"unmap", (XtActionProc) Unmap},
89 {"leave", (XtActionProc) Leave},
93 /****************************************************************
95 * MenuPane Resources
97 ****************************************************************/
99 static XtResource resources[] = {
100 {XtNtitlePosition, XtCTitlePosition, XtRTitlePositionType, sizeof(int),
101 XtOffset(XwCascadeWidget, cascade.titlePosition),XtRString,"top"},
105 /****************************************************************
107 * Full class record constant
109 ****************************************************************/
111 XwCascadeClassRec XwcascadeClassRec = {
113 /* core_class fields */
114 /* superclass */ (WidgetClass) &XwmenupaneClassRec,
115 /* class_name */ "XwCascade",
116 /* widget_size */ sizeof(XwCascadeRec),
117 /* class_initialize */ NULL,
118 /* class_part_init */ NULL,
119 /* class_inited */ FALSE,
120 /* initialize */ Initialize,
121 /* initialize_hook */ NULL,
122 /* realize */ Realize,
123 /* actions */ actionsList,
124 /* num_actions */ XtNumber(actionsList),
125 /* resources */ resources,
126 /* num_resources */ XtNumber(resources),
127 /* xrm_class */ NULLQUARK,
128 /* compress_motion */ TRUE,
129 /* compress_exposure */ TRUE,
130 /* compress_enterlv */ TRUE,
131 /* visible_interest */ FALSE,
132 /* destroy */ NULL,
133 /* resize */ Resize,
134 /* expose */ Redisplay,
135 /* set_values */ SetValues,
136 /* set_values_hook */ NULL,
137 /* set_values_almost */ XtInheritSetValuesAlmost,
138 /* get_values_hook */ NULL,
139 /* accept_focus */ NULL,
140 /* version */ XtVersion,
141 /* PRIVATE cb list */ NULL,
142 /* tm_table */ defaultTranslations,
143 /* query_geometry */ NULL,
144 /* display_accelerator */ XtInheritDisplayAccelerator,
145 /* extension */ NULL
147 /* composite_class fields */
148 /* geometry_manager */ GeometryManager,
149 /* change_managed */ ChangeManaged,
150 /* insert_child */ XtInheritInsertChild,
151 /* delete_child */ XtInheritDeleteChild,
152 NULL
154 /* constraint class fields */
155 /* resources */ NULL,
156 /* num_resources */ 0,
157 /* constraint_size */ sizeof (Boolean),
158 /* initialize */ (XtInitProc)XtInheritMenuPaneConstraintInit,
159 /* destroy */ NULL,
160 /* set_values */ NULL,
161 NULL
163 /* manager_class fields */
164 /* traversal handler */ (XwTraversalProc)XtInheritTraversalProc,
165 /* translations */ NULL
167 /* menu pane class - none */
168 /* setTraversalFlag */ XtInheritSetTraversalFlagProc
170 /* cascade class - none */
171 /* mumble */ 0
175 WidgetClass XwcascadeWidgetClass = (WidgetClass)&XwcascadeClassRec;
178 /*************************************<->*************************************
180 * Select ()
182 * Description:
183 * -----------
184 * Called upon receipt of a 'select' action; simple invokes callbacks.
187 * Inputs:
188 * ------
189 * xxxxxxxxxxxx = xxxxxxxxxxxxx
191 * Outputs:
192 * -------
193 * xxxxxxxxxxxx = xxxxxxxxxxxxx
195 * Procedures Called
196 * -----------------
198 *************************************<->***********************************/
200 static void Select (w, event)
202 Widget w;
203 XEvent * event;
206 Widget parent, grandparent;
208 if ((parent = XtParent(w)) &&
209 (grandparent = XtParent(parent)) &&
210 (XtIsSubclass (grandparent, XwmenumgrWidgetClass)))
212 /* Ask the menu mgr if we should process or ignore the select */
213 if ((*((XwMenuMgrWidgetClass)XtClass(grandparent))->menu_mgr_class.
214 processSelect) (grandparent, w, event) == FALSE)
216 return;
220 XtCallCallbacks (w, XtNselect, NULL);
224 /*************************************<->*************************************
226 * Leave()
228 * Description:
229 * -----------
230 * Called upon receipt of a LeaveNotify event; this is a NOOP, whose
231 * purpose is to simply prevent us from using the LeaveNotify handler
232 * supplied by the Manager class. The Manager's action routine does
233 * an XSetInputFocus() to root, which is not what we want here.
236 * Inputs:
237 * ------
238 * xxxxxxxxxxxx = xxxxxxxxxxxxx
240 * Outputs:
241 * -------
242 * xxxxxxxxxxxx = xxxxxxxxxxxxx
244 * Procedures Called
245 * -----------------
247 *************************************<->***********************************/
249 static void Leave (w, event)
251 Widget w;
252 XEvent * event;
258 /*************************************<->*************************************
260 * GetIdealSize
262 * Description:
263 * -----------
264 * Returns the minimum height and width into which the menu pane will fit.
265 * replyHeight and replyWidth are set to the minimum acceptable size.
266 * Also, the maxCascadeWidth, maxLabel and largestButtonWidth fields are
267 * set in the widget structure.
270 * Inputs:
271 * ------
272 * xxxxxxxxxxxx = xxxxxxxxxxxxx
274 * Outputs:
275 * -------
276 * xxxxxxxxxxxx = xxxxxxxxxxxxx
278 * Procedures Called
279 * -----------------
281 *************************************<->***********************************/
283 static GetIdealSize(mw, replyWidth, replyHeight)
285 XwCascadeWidget mw;
286 Dimension *replyWidth, *replyHeight; /* RETURN */
289 Cardinal i;
290 Dimension minWidth, minHeight, largestButtonWidth;
291 XwMenuButtonWidget menuButton; /* Current button */
292 Dimension idealWidth;
296 * First, compute the minimum width (less padding) needed for
297 * these items; include the title in these calculations.
300 minWidth = largestButtonWidth = 0;
301 minHeight = mw->manager.highlight_thickness << 1;
303 if (mw->menu_pane.title_showing && !mw->menu_pane.title_override)
305 if (mw->menu_pane.title_type == XwSTRING)
307 minWidth = mw->cascade.title_width +
308 PADDING_TO_LEFT +
309 PADDING_TO_RIGHT;
310 largestButtonWidth = minWidth;
311 if (mw->cascade.titlePosition & XwTOP)
313 minHeight += mw->cascade.title_height +
314 PADDING_FROM_ABOVE +
315 PADDING_FOR_UNDERLINE +
316 DOUBLE_LINES;
318 if (mw->cascade.titlePosition & XwBOTTOM)
320 minHeight += mw->cascade.title_height +
321 PADDING_FROM_BELOW +
322 PADDING_FOR_UNDERLINE +
323 DOUBLE_LINES;
326 else
328 minWidth = mw->cascade.title_width +
329 PADDING_TO_LEFT +
330 PADDING_TO_RIGHT;
331 largestButtonWidth = minWidth;
332 if (mw->cascade.titlePosition & XwTOP)
334 minHeight += mw->cascade.title_height +
335 PADDING_FROM_ABOVE +
336 PADDING_FOR_UNDERLINE +
337 DOUBLE_LINES;
339 if (mw->cascade.titlePosition & XwBOTTOM)
341 minHeight += mw->cascade.title_height +
342 PADDING_FROM_BELOW +
343 PADDING_FOR_UNDERLINE +
344 DOUBLE_LINES;
349 minWidth += mw->manager.highlight_thickness << 1;
353 * Determine the ideal size for each button; keep track of largest button
356 for (i=0; i < mw->manager.num_managed_children; i++)
358 menuButton = (XwMenuButtonWidget) mw->manager.managed_children[i];
361 * If we are in the middle of a geometry request from one of
362 * our children, then we need to use the ideal size of the
363 * requesting widget, instead of the current widget. Otherwise,
364 * ask the widget for its ideal size.
366 if ((Widget) menuButton == mw->cascade.georeqWidget)
367 idealWidth = mw->cascade.georeqWidth;
368 else if (XtIsSubclass ((Widget)menuButton, XwmenubuttonWidgetClass))
370 (*(((XwMenuButtonWidgetClass)XtClass(menuButton))->
371 menubutton_class.idealWidthProc))((Widget)menuButton, &idealWidth);
373 else
374 idealWidth = menuButton->core.width;
376 minWidth = Max (minWidth, idealWidth +
377 (mw->manager.highlight_thickness << 1) +
378 (menuButton->core.border_width << 1));
379 largestButtonWidth = Max (largestButtonWidth, idealWidth);
380 minHeight += menuButton->core.height +
381 (menuButton->core.border_width << 1);
385 /* Set up return values */
386 if (minWidth == 0) minWidth = 1;
387 if (minHeight == 0) minHeight = 1;
389 if (replyWidth != NULL) *replyWidth = minWidth;
390 if (replyHeight != NULL) *replyHeight = minHeight;
392 mw->cascade.idealHeight = minHeight;
393 mw->cascade.idealWidth = minWidth;
394 mw->cascade.largestButtonWidth = largestButtonWidth;
398 /*************************************<->*************************************
400 * ProcedureName (parameters)
402 * Description:
403 * -----------
404 * Returns the minimum height and width into which the menu pane will fit.
405 * If the current menu pane size is small than this, then FALSE is
406 * returned; else, TRUE is returned. In all cases, replyHeight and
407 * replyWidth are set to the minimum acceptable size.
410 * Inputs:
411 * ------
412 * xxxxxxxxxxxx = xxxxxxxxxxxxx
414 * Outputs:
415 * -------
416 * xxxxxxxxxxxx = xxxxxxxxxxxxx
418 * Procedures Called
419 * -----------------
421 *************************************<->***********************************/
423 static Boolean PreferredSize(mw, width, height, replyWidth, replyHeight)
424 XwCascadeWidget mw;
425 Dimension width, height;
426 Dimension *replyWidth, *replyHeight;
428 GetIdealSize(mw, replyWidth, replyHeight);
430 return ((*replyWidth <= width) && (*replyHeight <= height));
434 /*************************************<->*************************************
436 * ProcedureName (parameters)
438 * Description:
439 * -----------
440 * This routine assumes the menu pane size has already been updated in
441 * the core record. It will simply relayout the menu buttons, to fit
442 * the new menu pane size. This is called when XtResizeWidget() is invoked,
443 * and when our own geometry manager tries to change our size because one
444 * of our children is trying to change its size.
447 * Inputs:
448 * ------
449 * xxxxxxxxxxxx = xxxxxxxxxxxxx
451 * Outputs:
452 * -------
453 * xxxxxxxxxxxx = xxxxxxxxxxxxx
455 * Procedures Called
456 * -----------------
458 *************************************<->***********************************/
460 static void Resize(mw)
462 XwCascadeWidget mw;
465 Cardinal i;
466 Cardinal xPos, yPos;
467 Dimension oldHeight;
468 XwMenuButtonWidget menuButton; /* Current button */
469 Dimension cascadeWidth, labelX;
472 /* Recalculate where the title string should be displayed */
473 mw->cascade.title_x = ((mw->core.width >> 1) +
474 mw->manager.highlight_thickness) -
475 (mw->cascade.title_width >> 1);
477 /* This is a two step process: first move the item, then resize it */
478 xPos = mw->manager.highlight_thickness;
479 yPos = mw->cascade.button_starting_loc;
481 for (i = 0; i < mw->manager.num_managed_children; i++)
483 menuButton = (XwMenuButtonWidget) mw->manager.managed_children[i];
484 XtMoveWidget ((Widget)menuButton, xPos, yPos);
487 * The following kludge will force the widget's resize routine
488 * to always be called.
490 oldHeight = menuButton->core.height;
491 menuButton->core.height = 0;
492 menuButton->core.width = 0;
494 XtResizeWidget ((Widget)menuButton,
495 mw->cascade.largestButtonWidth,
496 oldHeight,
497 menuButton->core.border_width);
499 yPos += menuButton->core.height +
500 (menuButton->core.border_width << 1);
503 SetTitleAttributes (mw, FALSE);
504 } /* Resize */
507 /*************************************<->*************************************
509 * TryNewLayout (parameters)
511 * Description:
512 * -----------
513 * This determines if the menu pane needs to change size. If it needs to
514 * get bigger, then it will ask its parent's geometry manager; if this
515 * succeeds, then the menu pane window will be resized (NOTE: the menu
516 * buttons are not touched yet). Also, if our resize request succeeded,
517 * the our parent's geometry manager will have updated our size fields
518 * in our core structure. This is called during a Change Manage request,
519 * and when one of our children issues a geometry request.
521 * NOTE: menu panes ALWAYS use their 'preferred' size.
524 * Inputs:
525 * ------
526 * xxxxxxxxxxxx = xxxxxxxxxxxxx
528 * Outputs:
529 * -------
530 * xxxxxxxxxxxx = xxxxxxxxxxxxx
532 * Procedures Called
533 * -----------------
535 *************************************<->***********************************/
537 static Boolean TryNewLayout(mw)
538 XwCascadeWidget mw;
540 XtWidgetGeometry request, reply;
541 XtGeometryResult r;
543 if ((mw->core.width == mw->cascade.idealWidth) &&
544 (mw->core.height == mw->cascade.idealHeight))
546 /* Same size */
547 return (TRUE);
551 switch (XtMakeResizeRequest ((Widget) mw, mw->cascade.idealWidth,
552 mw->cascade.idealHeight, NULL, NULL))
554 case XtGeometryYes:
555 return (TRUE);
557 case XtGeometryNo:
558 case XtGeometryAlmost:
559 return (FALSE);
562 return (FALSE);
566 /*************************************<->*************************************
568 * ProcedureName (parameters)
570 * Description:
571 * -----------
572 * Invoked when one of our children wants to change its size. This routine
573 * will automatically update the size fields within the child's core
574 * area.
577 * Inputs:
578 * ------
579 * xxxxxxxxxxxx = xxxxxxxxxxxxx
581 * Outputs:
582 * -------
583 * xxxxxxxxxxxx = xxxxxxxxxxxxx
585 * Procedures Called
586 * -----------------
588 *************************************<->***********************************/
590 /*ARGSUSED*/
591 static XtGeometryResult GeometryManager(w, request, reply)
592 Widget w;
593 XtWidgetGeometry *request;
594 XtWidgetGeometry *reply; /* RETURN */
597 Dimension width, height, borderWidth, junkH, junkW, newHeight;
598 XwCascadeWidget mw;
599 XtGeometryResult result = XtGeometryYes;
600 Boolean isPreferredSize;
601 int i;
604 * Since the manager is solely responsible for controlling the position
605 * of its children, any geometry request made which attempts to modify
606 * the child's position will not be satified; instead, a compromise will
607 * be returned, with the position bits cleared.
609 reply->request_mode = 0;
611 if (request->request_mode & (CWX | CWY))
612 result = XtGeometryAlmost;
614 mw = (XwCascadeWidget) w->core.parent;
617 /* Size changes must see if the new size can be accomodated */
618 if (request->request_mode & (CWWidth | CWHeight | CWBorderWidth)) {
620 /* Make all three fields in the request valid */
621 if ((request->request_mode & CWWidth) == 0)
622 request->width = w->core.width;
623 if ((request->request_mode & CWHeight) == 0)
624 request->height = w->core.height;
625 if ((request->request_mode & CWBorderWidth) == 0)
626 request->border_width = w->core.border_width;
628 /* Set the new size within the widget */
629 width = w->core.width;
630 height = w->core.height;
631 borderWidth = w->core.border_width;
632 w->core.width = request->width;
633 w->core.height = request->height;
634 w->core.border_width = request->border_width;
636 /* Calculate the new height needed to hold the menu */
637 newHeight = mw->core.height - (height + borderWidth) +
638 (request->height + request->border_width);
640 /* Let the layout routine know we are in the middle of a geo req */
641 mw->cascade.georeqWidget = w;
642 mw->cascade.georeqWidth = request->width;
644 /* See if we can allow this size request */
645 isPreferredSize = PreferredSize (mw, w->core.width +
646 (w->core.border_width << 1) +
647 (mw->manager.highlight_thickness << 1),
648 newHeight, &junkW, &junkH);
650 /* Cleanup */
651 mw->cascade.georeqWidget = (Widget) NULL;
654 * Only allow an item to shrink if it was the largest item.
655 * However, always allow the item to get bigger.
658 if (!isPreferredSize)
661 * The widget is attempting to make itself smaller than is allowed;
662 * therefore, we must return a compromise size, which we know will
663 * succeed.
665 reply->width = junkW - (mw->manager.highlight_thickness << 1) -
666 (w->core.border_width << 1);
667 reply->height = request->height;
668 reply->border_width = request->border_width;
669 reply->request_mode = CWWidth | CWHeight | CWBorderWidth;
670 result = XtGeometryAlmost;
672 /* Restore the previous size values */
673 w->core.width = width;
674 w->core.height = height;
675 w->core.border_width = borderWidth;
677 else
679 if (result == XtGeometryAlmost)
682 * Even though the size request succeeded, the request cannot
683 * be satisfied, since someone before us has already set the
684 * result to XtGeometryAlmost; most likely, it was because
685 * an attempt was made to change the X or Y values.
687 reply->width = request->width;
688 reply->height = request->height;
689 reply->border_width = request->border_width;
690 reply->request_mode = CWWidth | CWHeight | CWBorderWidth;
692 /* Restore the previous size values */
693 w->core.width = width;
694 w->core.height = height;
695 w->core.border_width = borderWidth;
697 else
700 * All components of the geometry request could be satisfied,
701 * so make all necessary adjustments, and return a 'Yes'
702 * response to the requesting widget.
704 TryNewLayout (mw);
705 Resize (mw);
706 /* SetTitleAttributes (mw, FALSE); */
707 width = w->core.width;
708 height = w->core.height;
709 borderWidth = w->core.border_width;
710 result = XtGeometryDone;
713 }; /* if any size changes requested */
716 * Stacking changes are always allowed. However, if the result has
717 * already been set to XtGeometryAlmost, then some portion of the
718 * request has already failed, so we need to copy the stacking request
719 * back into the 'reply' structure, so that they are not lost.
722 if (result == XtGeometryAlmost)
724 if (request->request_mode & CWSibling)
726 reply->request_mode |= CWSibling;
727 reply->sibling = request->sibling;
730 if (request->request_mode & CWStackMode)
732 reply->request_mode |= CWStackMode;
733 reply->stack_mode = request->stack_mode;
737 return (result);
741 /*************************************<->*************************************
743 * ChangeManaged
745 * Description:
746 * -----------
747 * Forces the managed_children list to be updated, and then attempts to
748 * relayout the menu buttons. If the menu pane is not large enough, then
749 * it will ask its geometry manager to enlarge it. This is invoked when
750 * a new child is managed, or an existing one is unmanaged. NOTE: only
751 * managed children which also have the mapped_when_managed flag set
752 * are included in the layout calculations.
755 * Inputs:
756 * ------
757 * xxxxxxxxxxxx = xxxxxxxxxxxxx
759 * Outputs:
760 * -------
761 * xxxxxxxxxxxx = xxxxxxxxxxxxx
763 * Procedures Called
764 * -----------------
766 *************************************<->***********************************/
768 static void ChangeManaged (mw)
769 XwCascadeWidget mw;
771 Widget parent, grandparent;
772 Widget menubutton;
773 int i;
774 Boolean * managedConstraintFlag;
776 /* Reconfigure the button box */
777 _XwSetMappedManagedChildrenList(mw);
778 SetTitleAttributes (mw, FALSE);
779 GetIdealSize(mw, NULL, NULL);
780 (void) TryNewLayout(mw);
781 Resize(mw);
784 * Tell the menu manager that the list of mapped & managed children
785 * has changed,
787 if ((parent = XtParent(mw)) &&
788 (grandparent = XtParent(parent)) &&
789 (XtIsSubclass (grandparent, XwmenumgrWidgetClass)))
791 (*((XwMenuMgrWidgetClass)XtClass(grandparent))->menu_mgr_class.
792 paneManagedChildren) (grandparent, (Widget)mw);
796 * The constraint record has been updated by the menu manager.
801 /*************************************<->*************************************
803 * Initialize
806 * Description:
807 * -----------
808 * Initialize the menu_pane fields within the widget's instance structure.
809 * Calls for registering the pane with a menu manager, and for attaching
810 * the pane to a menu button are handled by our meta class.
813 * Inputs:
814 * ------
815 * xxxxxxxxxxxx = xxxxxxxxxxxxx
817 * Outputs:
818 * -------
819 * xxxxxxxxxxxx = xxxxxxxxxxxxx
821 * Procedures Called
822 * -----------------
824 *************************************<->***********************************/
826 static void Initialize (request, new)
827 XwCascadeWidget request, new;
829 Arg args2[2];
831 new->cascade.georeqWidget = (Widget) NULL;
833 /* Determine the title attributes, and the starting location for our kids */
834 SetTitleAttributes (new, TRUE);
836 /* Force our parent shell to be resizable */
837 XtSetArg (args2[0], XtNallowShellResize, TRUE);
838 XtSetArg (args2[1], XtNoverrideRedirect, TRUE);
839 XtSetValues (new->core.parent, args2, XtNumber(args2));
841 /* Augment our translations to include the traversal actions */
842 XtAugmentTranslations ((Widget) new,
843 XwmanagerClassRec.manager_class.translations);
845 /* KLUDGE!!! This is necessary!!! The shell must be realized so
846 * that the cascades changed_managed routine is called and the
847 * keyboard accelerators are set up for the menu manager.
849 if (new->core.height > 0)
850 (new->core.parent)->core.height = new->core.height;
851 else
852 (new->core.parent)->core.height = 1;
854 if (new->core.width > 0)
855 (new->core.parent)->core.width = new->core.width;
856 else
857 (new->core.parent)->core.width = 1;
859 if (XtIsSubclass(new->core.parent, shellWidgetClass))
860 XtRealizeWidget (new->core.parent);
861 } /* Initialize */
863 /*************************************<->*************************************
865 * Realize
867 * Description:
868 * -----------
869 * Invoked only when the menu pane is realized. It will create the window
870 * in which the menu pane will be displayed.
873 * Inputs:
874 * ------
875 * xxxxxxxxxxxx = xxxxxxxxxxxxx
877 * Outputs:
878 * -------
879 * xxxxxxxxxxxx = xxxxxxxxxxxxx
881 * Procedures Called
882 * -----------------
884 *************************************<->***********************************/
886 static void Realize(w, p_valueMask, attributes)
887 register Widget w;
888 Mask *p_valueMask;
889 XSetWindowAttributes *attributes;
891 XwCascadeWidget mw;
892 Mask valueMask = *p_valueMask;
894 attributes->bit_gravity = ForgetGravity;
895 valueMask |= CWBitGravity;
896 mw = (XwCascadeWidget) w;
898 w->core.window =
899 XCreateWindow(XtDisplay(w), w->core.parent->core.window,
900 w->core.x, w->core.y, w->core.width, w->core.height,
901 w->core.border_width, w->core.depth,
902 InputOutput, (Visual *)CopyFromParent,
903 valueMask, attributes);
905 _XwRegisterName (w);
906 } /* Realize */
909 /*************************************<->*************************************
911 * SetValues
913 * Description:
914 * -----------
917 * Inputs:
918 * ------
919 * xxxxxxxxxxxx = xxxxxxxxxxxxx
921 * Outputs:
922 * -------
923 * xxxxxxxxxxxx = xxxxxxxxxxxxx
925 * Procedures Called
926 * -----------------
928 *************************************<->***********************************/
930 static Boolean SetValues (current, request, new)
931 XwCascadeWidget current, request, new;
933 Boolean redrawFlag = FALSE;
936 * We never allow our traversal flags to be changed during SetValues();
937 * this is enforced by our superclass.
940 /* Validate the title position, and see if it has changed */
942 if ((new->cascade.titlePosition & (XwTOP | XwBOTTOM)) == 0)
944 new->cascade.titlePosition = current->cascade.titlePosition;
945 XtWarning (
946 "Cascade: Invalid title position; resetting to previous setting");
949 if ((current->cascade.titlePosition & (XwTOP | XwBOTTOM)) !=
950 (new->cascade.titlePosition & (XwTOP | XwBOTTOM)))
952 redrawFlag = TRUE;
956 SetTitleAttributes (new, FALSE);
957 GetIdealSize(new, NULL, NULL);
958 new->core.height = new->cascade.idealHeight;
959 new->core.width = new->cascade.idealWidth;
962 * If the title position changes, but the size of the menupane
963 * does not (because no other attributes have changed which could
964 * cause the size to change), then we need to force a call to our
965 * resize() procedure, so that the menu buttons get repositioned
966 * relative to the new title position.
968 if (redrawFlag && (new->core.height == current->core.height) &&
969 (new->core.width == current->core.width))
971 Resize(new);
974 return (redrawFlag);
978 /*************************************<->*************************************
980 * Redisplay
982 * Description:
983 * -----------
986 * Inputs:
987 * ------
988 * xxxxxxxxxxxx = xxxxxxxxxxxxx
990 * Outputs:
991 * -------
992 * xxxxxxxxxxxx = xxxxxxxxxxxxx
994 * Procedures Called
995 * -----------------
997 *************************************<->***********************************/
999 static void Redisplay (w, event)
1000 Widget w;
1001 XEvent * event;
1003 XwCascadeWidget mw = (XwCascadeWidget) w;
1005 /* If a title is defined, then redisplay it, if 'showing' flag set */
1006 if (mw->menu_pane.title_showing && ! mw->menu_pane.title_override)
1009 /* Recalculate the title position */
1010 mw->cascade.title_x = (mw->core.width >> 1) +
1011 mw->manager.highlight_thickness -
1012 (mw->cascade.title_width >> 1);
1014 if (mw->menu_pane.title_type == XwSTRING)
1016 if (mw->cascade.titlePosition & XwTOP)
1018 XDrawString (XtDisplay(w), XtWindow(w), mw->menu_pane.titleGC,
1019 mw->cascade.title_x, mw->cascade.top_title_y,
1020 mw->menu_pane.title_string,
1021 XwStrlen(mw->menu_pane.title_string));
1023 XDrawLine (XtDisplay(w), XtWindow(w), mw->menu_pane.titleGC, 0,
1024 mw->cascade.top_title_y +
1025 mw->menu_pane.title_font->descent +
1026 PADDING_FOR_UNDERLINE + 1,
1027 mw->core.width,
1028 mw->cascade.top_title_y +
1029 mw->menu_pane.title_font->descent +
1030 PADDING_FOR_UNDERLINE + 1);
1032 XDrawLine (XtDisplay(w), XtWindow(w), mw->menu_pane.titleGC, 0,
1033 mw->cascade.top_title_y +
1034 mw->menu_pane.title_font->descent +
1035 PADDING_FOR_UNDERLINE + 3,
1036 mw->core.width,
1037 mw->cascade.top_title_y +
1038 mw->menu_pane.title_font->descent +
1039 PADDING_FOR_UNDERLINE + 3);
1042 if (mw->cascade.titlePosition & XwBOTTOM)
1044 XDrawString (XtDisplay(w), XtWindow(w), mw->menu_pane.titleGC,
1045 mw->cascade.title_x, mw->cascade.bottom_title_y,
1046 mw->menu_pane.title_string,
1047 XwStrlen(mw->menu_pane.title_string));
1049 XDrawLine (XtDisplay(w), XtWindow(w), mw->menu_pane.titleGC, 0,
1050 mw->cascade.bottom_title_y -
1051 mw->menu_pane.title_font->ascent -
1052 DOUBLE_LINES + 2,
1053 mw->core.width,
1054 mw->cascade.bottom_title_y -
1055 mw->menu_pane.title_font->ascent -
1056 DOUBLE_LINES + 2);
1058 XDrawLine (XtDisplay(w), XtWindow(w), mw->menu_pane.titleGC, 0,
1059 mw->cascade.bottom_title_y -
1060 mw->menu_pane.title_font->ascent -
1061 DOUBLE_LINES,
1062 mw->core.width,
1063 mw->cascade.bottom_title_y -
1064 mw->menu_pane.title_font->ascent -
1065 DOUBLE_LINES);
1068 else if (mw->menu_pane.titleImage)
1070 if (mw->cascade.titlePosition & XwTOP)
1072 XPutImage (XtDisplay(mw), XtWindow(mw), mw->menu_pane.titleGC,
1073 mw->menu_pane.titleImage, 0, 0,
1074 mw->cascade.title_x, mw->cascade.top_title_y,
1075 mw->cascade.title_width, mw->cascade.title_height);
1077 XDrawLine (XtDisplay(w), XtWindow(w), mw->menu_pane.titleGC, 0,
1078 mw->cascade.top_title_y +
1079 mw->cascade.title_height +
1080 PADDING_FOR_UNDERLINE + 1,
1081 mw->core.width,
1082 mw->cascade.top_title_y +
1083 mw->cascade.title_height +
1084 PADDING_FOR_UNDERLINE + 1);
1086 XDrawLine (XtDisplay(w), XtWindow(w), mw->menu_pane.titleGC, 0,
1087 mw->cascade.top_title_y +
1088 mw->cascade.title_height +
1089 PADDING_FOR_UNDERLINE + 3,
1090 mw->core.width,
1091 mw->cascade.top_title_y +
1092 mw->cascade.title_height +
1093 PADDING_FOR_UNDERLINE + 3);
1096 if (mw->cascade.titlePosition & XwBOTTOM)
1098 XPutImage (XtDisplay(mw), XtWindow(mw), mw->menu_pane.titleGC,
1099 mw->menu_pane.titleImage, 0, 0,
1100 mw->cascade.title_x, mw->cascade.bottom_title_y,
1101 mw->cascade.title_width, mw->cascade.title_height);
1103 XDrawLine (XtDisplay(w), XtWindow(w), mw->menu_pane.titleGC, 0,
1104 mw->cascade.bottom_title_y -
1105 DOUBLE_LINES + 2,
1106 mw->core.width,
1107 mw->cascade.bottom_title_y -
1108 DOUBLE_LINES + 2);
1110 XDrawLine (XtDisplay(w), XtWindow(w), mw->menu_pane.titleGC, 0,
1111 mw->cascade.bottom_title_y -
1112 DOUBLE_LINES,
1113 mw->core.width,
1114 mw->cascade.bottom_title_y -
1115 DOUBLE_LINES);
1123 /*************************************<->*************************************
1125 * SetTitleAttributes
1127 * Description:
1128 * -----------
1129 * This procedure calculates the height, width, and starting location
1130 * for the title string/image. In addition, it uses
1131 * this information to determine where the menu buttons should be laid
1132 * out within the pane.
1135 * Inputs:
1136 * ------
1137 * mw = The menu pane widget whose title attributes are being calculated.
1139 * setCoreFields = A boolean flag, indicating whether the core height
1140 * and width fields should be set to their default value.
1141 * This flag should only be set to TRUE when this routine
1142 * is invoked at initialization time; all other calls must
1143 * set this to FALSE.
1145 * Outputs:
1146 * -------
1147 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1149 * Procedures Called
1150 * -----------------
1152 *************************************<->***********************************/
1154 static void SetTitleAttributes (mw, setCoreFields)
1156 XwCascadeWidget mw;
1157 Boolean setCoreFields;
1161 if (mw->menu_pane.title_showing && !mw->menu_pane.title_override)
1163 if (mw->menu_pane.title_type == XwSTRING)
1165 /* Determine size of title string */
1166 mw->cascade.title_width = XTextWidth (mw->menu_pane.title_font,
1167 mw->menu_pane.title_string,
1168 XwStrlen(mw->menu_pane.title_string));
1169 mw->cascade.title_height = mw->menu_pane.title_font->ascent +
1170 mw->menu_pane.title_font->descent;
1171 mw->cascade.title_x = PADDING_TO_LEFT +
1172 mw->manager.highlight_thickness;
1174 /* Default size should contain just the title string */
1175 if (setCoreFields)
1177 mw->core.width = mw->cascade.title_width +
1178 (mw->manager.highlight_thickness << 1) +
1179 PADDING_TO_LEFT +
1180 PADDING_TO_RIGHT;
1181 mw->core.height = mw->manager.highlight_thickness << 1;
1182 if (mw->cascade.titlePosition & XwTOP)
1183 mw->core.height += mw->cascade.title_height +
1184 PADDING_FROM_ABOVE +
1185 PADDING_FOR_UNDERLINE +
1186 DOUBLE_LINES;
1187 if (mw->cascade.titlePosition & XwBOTTOM)
1188 mw->core.height += mw->cascade.title_height +
1189 PADDING_FROM_BELOW +
1190 PADDING_FOR_UNDERLINE +
1191 DOUBLE_LINES;
1194 if (mw->cascade.titlePosition & XwTOP)
1195 mw->cascade.top_title_y = PADDING_FROM_ABOVE +
1196 mw->manager.highlight_thickness +
1197 mw->menu_pane.title_font->ascent;
1198 else
1199 mw->cascade.top_title_y = 0;
1201 if (mw->cascade.titlePosition & XwBOTTOM)
1202 mw->cascade.bottom_title_y = mw->core.height -
1203 mw->manager.highlight_thickness -
1204 mw->menu_pane.title_font->descent -
1205 PADDING_FROM_ABOVE -
1206 PADDING_FOR_UNDERLINE;
1207 else
1208 mw->cascade.bottom_title_y = mw->core.height -
1209 mw->manager.highlight_thickness;
1211 if (mw->cascade.titlePosition & XwTOP)
1212 mw->cascade.button_starting_loc = mw->cascade.top_title_y +
1213 mw->menu_pane.title_font->descent +
1214 PADDING_FOR_UNDERLINE +
1215 DOUBLE_LINES;
1216 else
1217 mw->cascade.button_starting_loc = mw->manager.highlight_thickness;
1219 else if (mw->menu_pane.titleImage)
1221 /* Determine size of title image */
1222 mw->cascade.title_width = mw->menu_pane.titleImage->width;
1223 mw->cascade.title_height = mw->menu_pane.titleImage->height;
1224 mw->cascade.title_x = PADDING_TO_LEFT +
1225 mw->manager.highlight_thickness;
1227 /* Default size should contain just the title image */
1228 if (setCoreFields)
1230 mw->core.width = mw->cascade.title_width +
1231 (mw->manager.highlight_thickness << 1) +
1232 PADDING_TO_LEFT +
1233 PADDING_TO_RIGHT;
1234 mw->core.height = (mw->manager.highlight_thickness << 1);;
1235 if (mw->cascade.titlePosition & XwTOP)
1236 mw->core.height += mw->cascade.title_height +
1237 PADDING_FROM_ABOVE +
1238 PADDING_FOR_UNDERLINE +
1239 DOUBLE_LINES;
1240 if (mw->cascade.titlePosition & XwBOTTOM)
1241 mw->core.height += mw->cascade.title_height +
1242 PADDING_FROM_ABOVE +
1243 PADDING_FOR_UNDERLINE +
1244 DOUBLE_LINES;
1247 if (mw->cascade.titlePosition & XwTOP)
1248 mw->cascade.top_title_y = PADDING_FROM_ABOVE +
1249 mw->manager.highlight_thickness;
1250 else
1251 mw->cascade.top_title_y = 0;
1252 if (mw->cascade.titlePosition & XwBOTTOM)
1253 mw->cascade.bottom_title_y = mw->core.height -
1254 mw->manager.highlight_thickness -
1255 mw->cascade.title_height -
1256 PADDING_FROM_BELOW;
1257 else
1258 mw->cascade.bottom_title_y = mw->core.height -
1259 mw->manager.highlight_thickness;
1261 if (mw->cascade.titlePosition & XwTOP)
1262 mw->cascade.button_starting_loc = mw->cascade.top_title_y +
1263 mw->cascade.title_height +
1264 PADDING_FOR_UNDERLINE +
1265 DOUBLE_LINES;
1266 else
1267 mw->cascade.button_starting_loc = mw->manager.highlight_thickness;
1269 else
1271 /* No image is present */
1273 if (setCoreFields)
1275 mw->core.width = (mw->manager.highlight_thickness > 0) ?
1276 (mw->manager.highlight_thickness << 1) : 2;
1277 mw->core.height = mw->core.width;
1279 mw->cascade.title_width = 0;
1280 mw->cascade.title_height = 0;
1281 mw->cascade.title_x = 0;
1282 mw->cascade.top_title_y = 0;
1283 mw->cascade.bottom_title_y = mw->core.height;
1284 mw->cascade.button_starting_loc = mw->manager.highlight_thickness;
1287 else
1289 /* No image or string is present */
1291 if (setCoreFields)
1293 mw->core.width = (mw->manager.highlight_thickness > 0) ?
1294 (mw->manager.highlight_thickness << 1) : 2;
1295 mw->core.height = mw->core.width;
1297 mw->cascade.title_width = 0;
1298 mw->cascade.title_height = 0;
1299 mw->cascade.title_x = 0;
1300 mw->cascade.top_title_y = 0;
1301 mw->cascade.bottom_title_y = mw->core.height;
1302 mw->cascade.button_starting_loc = mw->manager.highlight_thickness;
1307 /*************************************<->*************************************
1309 * Visibility(parameters)
1311 * Description:
1312 * -----------
1313 * xxxxxxxxxxxxxxxxxxxxxxx
1316 * Inputs:
1317 * ------
1318 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1320 * Outputs:
1321 * -------
1322 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1324 * Procedures Called
1325 * -----------------
1327 *************************************<->***********************************/
1329 static void Visibility (widget, event)
1331 Widget widget;
1332 XEvent * event;
1336 * Noop; purpose is to prevent Manager's translation from
1337 * taking effect.
1342 /*************************************<->*************************************
1344 * Unmap(parameters)
1346 * Description:
1347 * -----------
1348 * xxxxxxxxxxxxxxxxxxxxxxx
1351 * Inputs:
1352 * ------
1353 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1355 * Outputs:
1356 * -------
1357 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1359 * Procedures Called
1360 * -----------------
1362 *************************************<->***********************************/
1364 static void Unmap (widget, event)
1366 Widget widget;
1367 XEvent * event;
1371 * Noop; purpose is to prevent Manager's translation from
1372 * taking effect.