source: trunk/third/mwm/WmMenu.c @ 9757

Revision 9757, 48.3 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r9756, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * (c) Copyright 1989, 1990, 1991, 1992, 1993 OPEN SOFTWARE FOUNDATION, INC.
3 * ALL RIGHTS RESERVED
4*/
5/*
6 * Motif Release 1.2.3
7*/
8#ifdef REV_INFO
9#ifndef lint
10static char rcsid[] = "$RCSfile: WmMenu.c,v $ $Revision: 1.1.1.1 $ $Date: 1997-03-25 09:12:22 $"
11#endif
12#endif
13/*
14 * (c) Copyright 1987, 1988, 1989, 1990 HEWLETT-PACKARD COMPANY */
15/*
16 * (c) Copyright 1987, 1988 DIGITAL EQUIPMENT CORPORATION */
17/*
18 * (c) Copyright 1988 MASSACHUSETTS INSTITUTE OF TECHNOLOGY */
19
20/*
21 * Included Files:
22 */
23
24#include "WmGlobal.h"
25#include "WmResource.h"
26#include "WmResParse.h"
27#include <stdio.h>
28
29#include <X11/Shell.h>
30
31#include <Xm/Xm.h>
32#include <Xm/XmP.h>
33#include <Xm/CascadeB.h>
34#include <Xm/CascadeBG.h>
35#include <Xm/Label.h>
36#include <Xm/LabelG.h>
37#include <Xm/MenuShell.h>
38#include <Xm/PushB.h>
39#include <Xm/PushBG.h>
40#include <Xm/RowColumn.h>
41#include <Xm/RowColumnP.h>
42#include <Xm/Separator.h>
43#include <Xm/SeparatoG.h>
44
45#define SHELL_NAME "menu"
46#define SEPARATOR_NAME "separator"
47#define TITLE_NAME "title_name"
48#define CASCADE_BTN_NAME "cascadebutton"
49#define PUSH_BTN_NAME "pushbutton"
50
51#define CHILDREN_CACHE  22
52#define MENU_BUTTON_INC 5
53
54/*
55 * include extern functions
56 */
57#include "WmMenu.h"
58#include "WmCDecor.h"
59#include "WmColormap.h"
60#include "WmEvent.h"
61#include "WmFunction.h"
62#include "WmIconBox.h"
63#include "WmImage.h"
64#include "WmError.h"
65
66#ifdef AUTOMATION
67#ifdef _NO_PROTO
68static void SetMwmMenuInfo ();
69static void SetMwmMenuWindow ();
70#else
71static void SetMwmMenuInfo (ClientData *pcd, MenuSpec *menuSpec);
72static void SetMwmMenuWindow (ClientData *pcd, Widget menuWidget);
73#endif /* _NO_PROTO */
74#endif /* AUTOMATION */
75
76
77
78
79/*************************************<->*************************************
80 *
81 *  MakeMenu (menuName, initialContext, accelContext, moreMenuItems,
82 *            fSystemMenu)
83 *
84 *
85 *  Description:
86 *  -----------
87 *  This function makes a menu widget.
88 *
89 *
90 *  Inputs:
91 *  ------
92 *  menuName       = name of the top-level menu pane for the menu
93 *  initialContext = initial context for menuitem sensitivity
94 *  accelContext   = accelerator context
95 *  moreMenuItems  = additional menuitems for custom menu.
96 *  fSystemMenu    = TRUE iff the menu is a client system menu.
97 *
98 *
99 *  Outputs:
100 *  -------
101 *  Return = pointer to a MenuSpec structure with updated currentContext,
102 *           menuWidget, and menuButtons members.
103 *
104 *
105 *  Comments:
106 *  --------
107 *  If moreMenuItems is nonNULL, a custom MenuSpec will be created, with
108 *  menuItem member pointing to moreMenuItems.  The menuItems for the
109 *  standard MenuSpec of the same name and the moreMenuItems list will be
110 *  used to create menubuttons, and the menu widget will be separate from
111 *  any existing standard menu widget.
112 *
113 *  When the client is destroyed, this custom MenuSpec, its menuItem and
114 *  menuButton lists, and its menu widget should be freed.
115 *
116 *************************************<->***********************************/
117#ifdef _NO_PROTO
118MenuSpec *
119MakeMenu (pSD, menuName, initialContext, accelContext,
120          moreMenuItems, fSystemMenu)
121
122    WmScreenData *pSD;
123    String    menuName;
124    Context   initialContext;
125    Context   accelContext;
126    MenuItem *moreMenuItems;
127    Boolean   fSystemMenu;
128#else /* _NO_PROTO */
129MenuSpec *MakeMenu (WmScreenData *pSD, String menuName, Context initialContext,
130                    Context accelContext, MenuItem *moreMenuItems,
131                    Boolean fSystemMenu)
132#endif /* _NO_PROTO */
133{
134    unsigned int n;
135    MenuSpec     *menuSpec;
136    MenuSpec     *newMenuSpec;
137    MenuItem     *menuItem;
138    KeySpec      *accelKeySpec;
139   
140    if ((menuName == NULL) || (pSD == NULL))
141    {
142        return (NULL);
143    }
144
145    /*
146     * Look for the menu specification:
147     */
148
149    menuSpec = pSD->menuSpecs;
150    while (menuSpec)
151    {
152        if ((menuSpec->name != NULL) && !strcmp (menuSpec->name, menuName))
153        /* Found the menu pane. */
154        {
155            break;
156        }
157        menuSpec = menuSpec->nextMenuSpec;
158    }
159   
160    if (menuSpec == NULL)
161    /* the menuSpecs list is exhausted */
162    {
163        MWarning("Menu specification %s not found\n", menuName);
164        return (NULL);
165    }
166
167    /*
168     * The top-level menu pane specification was found.
169     * Adjust the menu accelerator context?
170     */
171
172    if (fSystemMenu)
173    {
174        accelContext = 0;
175    }
176    else if (accelContext & F_CONTEXT_ROOT)
177    /* root context accelerators apply everywhere */
178    {
179        accelContext = F_CONTEXT_ALL;
180    }
181
182    /*
183     * If making a custom menu, create a custom copy of the specification with
184     *   which to build the custom menu.
185     * Otherwise, if the menu widget exists, possibly modify the accelerator
186     *   contexts and return the specification.
187     */
188
189    if (moreMenuItems != NULL)
190    {
191        if ((newMenuSpec = (MenuSpec *) XtMalloc (sizeof (MenuSpec))) == NULL)
192        /* Handle insufficent memory */
193        {
194            MWarning("Insufficient memory for menu %s\n", menuName);
195            return (NULL);
196        }
197        newMenuSpec->name = NULL;  /* distinguishes this as custom */
198        newMenuSpec->whichButton = SELECT_BUTTON;
199        newMenuSpec->height = 0;
200        newMenuSpec->menuItems = menuSpec->menuItems; /* temporary */
201        newMenuSpec->accelContext = menuSpec->accelContext;
202        newMenuSpec->accelKeySpecs = NULL;
203        newMenuSpec->nextMenuSpec = NULL;
204        menuSpec = newMenuSpec;
205    }
206    else if (menuSpec->menuWidget)
207    {
208        /*
209         * OR the accelContext into the accelerators, if necessary.
210         */
211        if (accelContext != (menuSpec->accelContext & accelContext))
212        {
213            menuSpec->accelContext |= accelContext;
214            accelKeySpec = menuSpec->accelKeySpecs;
215            while (accelKeySpec)
216            {
217                accelKeySpec->context |= accelContext;
218                accelKeySpec = accelKeySpec->nextKeySpec;
219            }
220        }
221        return (menuSpec);
222    }
223
224    /*
225     * We have a menu specification with which to build the menu.
226     * Set the initial and accelerator contexts -- they are needed within
227     *   CreateMenuWidget.
228     */
229
230    menuSpec->currentContext = initialContext;
231    menuSpec->accelContext = accelContext;
232
233    /*
234     * Scan the toplevel MenuSpec and create its initial menuButtons array
235     * if any of its items will need to be included.  This array will be
236     * created or enlarged within CreateMenuWidget below if necessary.
237     */
238
239    n = 0;
240    menuItem = menuSpec->menuItems;
241    while (menuItem)
242    {
243        if ((menuItem->greyedContext) || (menuItem->mgtMask))
244        {
245            n++;
246        }
247        menuItem = menuItem->nextMenuItem;
248    }
249    menuItem = moreMenuItems;
250    while (menuItem)
251    {
252        if ((menuItem->greyedContext) || (menuItem->mgtMask))
253        {
254            n++;
255        }
256        menuItem = menuItem->nextMenuItem;
257    }
258    if (n)
259    {
260        if ((menuSpec->menuButtons =
261               (MenuButton *) XtMalloc (n * sizeof(MenuButton))) == NULL)
262        /* insufficent memory */
263        {
264            MWarning("Insufficient memory for menu %s\n", menuName);
265            return (NULL);
266        }
267        menuSpec->menuButtonSize = n;
268    }
269    else
270    {
271        menuSpec->menuButtons = NULL;
272        menuSpec->menuButtonSize = 0;
273    }
274    menuSpec->menuButtonCount = 0;
275
276    /*
277     * Create a PopupShell widget as a child of the workspace manager widget
278     *   and a PopupMenu as a child of the shell.
279     * Fill the PopupMenu with the menu items.
280     */
281
282    menuSpec->menuWidget = CreateMenuWidget (pSD, menuName,
283                                             pSD->screenTopLevelW,
284                                             TRUE, menuSpec, moreMenuItems);
285    if (menuSpec->menuWidget == NULL)
286    {
287        /*
288         *  Could not make the top-level menu pane.
289         */
290        return (NULL);
291    }
292/*
293    _XmSetPopupMenuClick(menuSpec->menuWidget, False);
294*/
295    /* Return the top MenuSpec */
296
297    return (menuSpec);
298
299} /* END OF FUNCTION MakeMenu */
300
301
302
303/*************************************<->***********************************/
304void CheckTerminalSeparator(menuSpec, buttonWidget, manage)
305     MenuSpec *menuSpec;
306     Widget buttonWidget;
307     Boolean manage;
308{
309    CompositeWidget cw;
310    WidgetList      children;
311    Cardinal        wPos;
312
313
314    if ((menuSpec == NULL) || (menuSpec->menuWidget == NULL))
315      {
316         return;
317      }
318
319    cw = (CompositeWidget)menuSpec->menuWidget;
320    children = cw->composite.children;
321
322    for (wPos = 0;  wPos < cw->composite.num_children; wPos++)
323    {
324        if((Widget)children[wPos] == buttonWidget)
325        {
326            break;
327        }
328    }
329   
330   
331    if(wPos > 0 &&
332       XtClass((Widget) children[wPos -1]) == xmSeparatorGadgetClass)
333    {
334        if(manage)
335        {
336            if (!(XtIsManaged((Widget)children[wPos -1])))
337            {
338                XtManageChild((Widget)children[wPos -1]);
339            }
340        }
341        else
342        {
343            if (XtIsManaged((Widget)children[wPos -1]))
344            {
345                XtUnmanageChild((Widget)children[wPos -1]);
346            }
347        }
348    }
349
350} /* END OF FUNCTION CheckTerminalSeparator */
351
352
353
354/*************************************<->*************************************
355 *
356 *  static Boolean
357 *  AdjustPBs (menuSpec, pCD, newContext)
358 *
359 *
360 *  Description:
361 *  -----------
362 *  This procedure adjusts menu PushButton sensitivities and manage/unmanaged
363 *  status for a toplevel menu.
364 *
365 *
366 *  Inputs:
367 *  ------
368 *  menuSpec =    nonNULL toplevel menu specification with gadget
369 *  pCD =         client data
370 *  newContext =  context that the menu is to be posted under.
371 *
372 *
373 *  Outputs:
374 *  -------
375 *  menuSpec =      menu specification with modifications
376 *  Return =        TRUE iff at least one menu item changed manage status.
377 *
378 *
379 *  Comments:
380 *  --------
381 *  Adjusts PushButton sensitivity according to context and function type.
382 *  Manages/Unmanages PushButtons according to clientFunction resource.
383 *
384 *************************************<->***********************************/
385#ifdef _NO_PROTO
386static Boolean AdjustPBs (menuSpec, pCD, newContext)
387    MenuSpec    *menuSpec;      /* RETURNED */
388    ClientData  *pCD;
389    Context      newContext;
390
391#else /* NO_PROTO */
392static Boolean AdjustPBs (MenuSpec *menuSpec, ClientData  *pCD,
393                          Context newContext)
394#endif /* _NO_PROTO */
395{
396    MenuButton    *menuButton;
397    MenuItem      *menuItem;
398    int            msgc;
399    unsigned int   n;
400    long          *pMsg;
401    Boolean        fSupported;
402    Boolean        fChangeManaged = FALSE;
403
404    /*
405     *  Set PushButton sensitivity.
406     *  Set f.send_msg button sensitivity according to context and client
407     *  message list.  Adjust other button sensitivities only for context.
408     */
409
410    /* check for bad input value - shouldn't happen. */
411    if (menuSpec == NULL) return (FALSE);
412
413    for (n = 0, menuButton = menuSpec->menuButtons;
414         n < menuSpec->menuButtonCount;
415         n++, menuButton++)
416    {
417        menuItem = menuButton->menuItem;
418        if (menuItem->wmFunction == F_Send_Msg)
419        /* f.send_msg button:  set according to context and message. */
420        {
421            if ((newContext & menuItem->greyedContext) ||
422                !(pCD && pCD->mwmMessagesCount && pCD->mwmMessages))
423            /* insensitive context or empty client message list */
424            {
425                XtSetSensitive (menuButton->buttonWidget, FALSE);
426            }
427            else
428            /*
429             * Have a context sensitive f.send_msg item and a client with a
430             * nonempty message list.  Set sensitive only if the message is
431             * supported by this client.  Otherwise set insensitive.
432             */
433            {
434                msgc = pCD->mwmMessagesCount;
435                pMsg = pCD->mwmMessages;
436                fSupported = FALSE;
437                while (msgc--)
438                /* scan nonempty message list */
439                {
440                    if (*pMsg == (long) menuItem->wmFuncArgs)
441                    /* found match */
442                    {
443                        fSupported = TRUE;
444                        break;
445                    }
446                    pMsg++;  /* next message in list */
447                }
448                XtSetSensitive (menuButton->buttonWidget, fSupported);
449            }
450        }
451        else
452        /*
453         * Non f.send_msg button:
454         *  Adjust sensitivity according to context.
455         *  Manage/Unmanage according to clientFunction.
456         */
457        {
458            if (menuSpec->currentContext & menuItem->greyedContext)
459            /* button is currently insensitive */
460            {
461                if (!(newContext & menuItem->greyedContext))
462                /* insensitive -> sensitive */
463                {
464                    XtSetSensitive (menuButton->buttonWidget, TRUE);
465                }
466            }
467            else
468            /* button is currently sensitive */
469            {
470                if (newContext & menuItem->greyedContext)
471                /* sensitive -> insensitive */
472                {
473                    XtSetSensitive (menuButton->buttonWidget, FALSE);
474                }
475            }
476
477            if ((menuItem->mgtMask) && pCD)
478            /* PushButton might not apply */
479            {
480                if (pCD->clientFunctions & menuItem->mgtMask)
481                /* function applies -- manage it */
482                {
483                    if (!menuButton->managed)
484                    /* unmanaged -> managed */
485                    {
486                        XtManageChild (menuButton->buttonWidget);
487                        menuButton->managed = TRUE;
488                        fChangeManaged = TRUE;
489                        if (n == menuSpec->menuButtonCount - 1)
490                        {
491                            /*
492                             * last item, if it has a separator before
493                             * it, manage the separator
494                             */
495                           
496                            CheckTerminalSeparator(menuSpec,
497                                                   menuButton->buttonWidget,
498                                                   True);
499                        }
500                    }
501                }
502                else
503                /* function does not apply -- unmanage it */
504                {
505                    if (menuButton->managed)
506                    /* managed -> unmanaged */
507                    {
508                        XtUnmanageChild (menuButton->buttonWidget);
509                        menuButton->managed = FALSE;
510                        fChangeManaged = TRUE;
511
512                        if (n == menuSpec->menuButtonCount - 1)
513                        {
514                            /*
515                             * last item, if it has a separator before
516                             * it, unmanage the separator
517                             */
518                            CheckTerminalSeparator(menuSpec,
519                                                   menuButton->buttonWidget,
520                                                   False);
521                        }
522
523                    }
524                }
525            }
526            else if (!menuButton->managed)
527            /* unmanaged PushButton applies */
528            {
529                XtManageChild (menuButton->buttonWidget);
530                menuButton->managed = TRUE;
531                fChangeManaged = TRUE;
532            }
533        }
534    }
535#ifdef AUTOMATION
536        SetMwmMenuInfo(pCD, menuSpec);
537#endif
538
539    return (fChangeManaged);
540
541} /* END OF FUNCTION AdjustPBs */
542
543
544
545/*************************************<->*************************************
546 *
547 *  static Boolean
548 *  SavePBInfo (topMenuSpec, menuItem, itemW)
549 *
550 *
551 *  Description:
552 *  -----------
553 *  Fills a MenuButton structure for a PushButton.
554 *  If necessary, mallocs or reallocs the menuButtons array in the toplevel
555 *  MenuSpec.
556 *
557 *
558 *  Inputs:
559 *  ------
560 *  topMenuSpec = pointer to toplevel MenuSpec structure
561 *  menuItem    = pointer to PushButton MenuItem structure
562 *  itemW       = PushButton gadget
563 *  topMenuSpec->menuButtons[]
564 *  topMenuSpec->menuButtonSize
565 *  topMenuSpec->menuButtonCount
566 *
567 *
568 *  Outputs:
569 *  -------
570 *  Return = FALSE iff insufficient memory for malloc or realloc
571 *           or bad input value forces exit.
572 *  topMenuSpec->menuButtons[]
573 *  topMenuSpec->menuButtonSize
574 *  topMenuSpec->menuButtonCount
575 *
576 *
577 *  Comments:
578 *  --------
579 *  The initial managed status of PushButtons is TRUE.
580 *
581 *************************************<->***********************************/
582#ifdef _NO_PROTO
583static Boolean SavePBInfo (topMenuSpec, menuItem, itemW)
584
585    MenuSpec *topMenuSpec;      /* RETURNED */
586    MenuItem *menuItem;
587    Widget    itemW;
588#else /* _NO_PROTO */
589static Boolean SavePBInfo (MenuSpec *topMenuSpec, MenuItem *menuItem,
590                             Widget itemW)
591#endif /* _NO_PROTO */
592{
593    MenuButton *menuButton;
594
595
596    /* check for bad input value - shouldn't happen. */
597    if (topMenuSpec == NULL) return (FALSE);
598
599    if (topMenuSpec->menuButtonSize == 0)
600    /* need to create array */
601    {
602        topMenuSpec->menuButtonSize = MENU_BUTTON_INC;
603        topMenuSpec->menuButtons =
604            (MenuButton *) XtMalloc (MENU_BUTTON_INC * sizeof(MenuButton));
605    }
606    else if (topMenuSpec->menuButtonCount == topMenuSpec->menuButtonSize)
607    /* need larger array */
608    {
609        topMenuSpec->menuButtonSize += MENU_BUTTON_INC;
610        topMenuSpec->menuButtons = (MenuButton *)
611            XtRealloc ((char*)topMenuSpec->menuButtons,
612                     topMenuSpec->menuButtonSize * sizeof(MenuButton));
613    }
614
615    if (topMenuSpec->menuButtons == NULL)
616    /* insufficent memory */
617    {
618        topMenuSpec->menuButtonSize = 0;
619        topMenuSpec->menuButtonCount = 0;
620        return (FALSE);
621    }
622
623    menuButton = &(topMenuSpec->menuButtons[topMenuSpec->menuButtonCount]);
624    topMenuSpec->menuButtonCount++;
625
626    menuButton->menuItem = menuItem;
627    menuButton->buttonWidget = itemW;
628    menuButton->managed = TRUE;
629    return (TRUE);
630
631}
632
633
634
635/*************************************<->*************************************
636 *
637 *  CreateMenuWidget (pSD, menuName, parent, fTopLevelPane, topMenuSpec,
638 *                    moreMenuItems)
639 *
640 *
641 *  Description:
642 *  -----------
643 *  Creates a MenuShell as a child of the specified parent widget, and a
644 *  PopupMenu or PulldownMenu as a child of the shell.  Fill the menu with
645 *  the named menupane items.
646 *
647 *
648 *  Inputs:
649 *  ------
650 *  pSD ---------- pointer to screen data
651 *  menuName ----- the name of the menu specification to be used to create
652 *                 the menu widget.
653 *  parent -------- parent of popup shell
654 *  fTopLevelPane - TRUE iff the menupane is a top level one
655 *  topMenuSpec --- pointer to the top menu specification.
656 *  moreMenuItems - pointer to additional menu items for custom menu.
657 *
658 *
659 *  Outputs:
660 *  -------
661 *  Return = created PopupMenu or PulldownMenu widget, or NULL.
662 *
663 *
664 *  Comments:
665 *  --------
666 *  We attach a popdowncallback to the menu to set wmGD.menuActive to NULL,
667 *  allowing us to not dispatch key events separately from the toolkit
668 *  dispatcher.
669 *
670 *************************************<->***********************************/
671
672typedef struct _StrList
673{
674   XmString         string;
675   struct _StrList *next;
676} StrList;
677
678#ifdef _NO_PROTO
679Widget CreateMenuWidget (pSD, menuName, parent, fTopLevelPane,
680                         topMenuSpec, moreMenuItems)
681    WmScreenData *pSD;
682    String    menuName;
683    Widget    parent;
684    Boolean   fTopLevelPane;
685    MenuSpec *topMenuSpec;
686    MenuItem *moreMenuItems;
687#else /* _NO_PROTO */
688Widget CreateMenuWidget (WmScreenData *pSD, String menuName, Widget parent,
689                         Boolean fTopLevelPane, MenuSpec *topMenuSpec,
690                         MenuItem *moreMenuItems)
691#endif /* _NO_PROTO */
692{
693    int         i, n;
694    Arg         sepArgs[1];
695    Arg         args[10];
696    MenuSpec   *menuSpec;
697    MenuItem   *menuItem;
698    Widget      menuShellW;
699    Widget      menuW;
700    Widget      subMenuW;
701    Widget      children[CHILDREN_CACHE];
702    Pixmap      labelPixmap;
703    KeySpec    *accelKeySpec;
704    Dimension   menuHeight;
705    Boolean     fUseTitleSep = FALSE;
706    StrList    *stringsToFree = NULL, *sPtr;
707    XmString    tmpstr;
708
709
710    /* check for bad input values. */
711    if ((menuName == NULL) || (pSD == NULL))
712    {
713        return (NULL);
714    }
715
716    /*
717     *  Find the menu pane specifications for menuName.
718     *  The top-level menu specification is passed as an argument (it may
719     *  be custom).  A submenu specification must be found and might not exist.
720     *  Return NULL if a submenu specification is not found.
721     */
722    if (fTopLevelPane)
723    {
724        menuSpec = topMenuSpec;
725    }
726    else
727    {
728        menuSpec = pSD->menuSpecs;
729        while (menuSpec)
730        {
731            if ((menuSpec->name != NULL) && !strcmp (menuSpec->name, menuName))
732            {
733                break;  /* found menuName's specification */
734            }
735            menuSpec = menuSpec->nextMenuSpec;  /* keep looking */
736        }
737    }
738
739    if (menuSpec == NULL)
740    /* (submenu) specification not found */
741    {
742        MWarning("Menu specification %s not found\n", menuName);
743        return (NULL);
744    }
745
746    /*
747     * If menuSpec is marked, we have menu recursion => fail.
748     *  Otherwise, mark it.
749     */
750
751    if (menuSpec->currentContext & CR_MENU_MARK)   /* marked? */
752    /* menu recursion */
753    {
754        MWarning("Menu recursion detected for %s\n", menuName);
755        return (NULL);
756    }
757    menuSpec->currentContext |= CR_MENU_MARK;   /* no, mark it */
758
759    /*
760     * Create a PopupShell widget.
761     * If the parent of the specified parent ("grandparent") is a MenuShell
762     * widget, then use the grandparent as the parent of the PopupShell.
763     * Otherwise, use the specified parent.
764     */
765    i = 0;
766    XtSetArg (args[i], XmNwidth, (XtArgVal) 5); i++;
767    XtSetArg (args[i], XmNheight, (XtArgVal) 5); i++;
768    XtSetArg (args[i], XmNallowShellResize, (XtArgVal) TRUE); i++;
769    XtSetArg (args[i], XtNoverrideRedirect, (XtArgVal) TRUE); i++;
770    XtSetArg (args[i], XtNdepth,
771                (XtArgVal) DefaultDepth(DISPLAY, pSD->screen)); i++;
772    XtSetArg (args[i], XtNscreen,
773                (XtArgVal) ScreenOfDisplay(DISPLAY, pSD->screen)); i++;
774
775    if ((XtParent (parent) != NULL) && XmIsMenuShell (XtParent (parent)))
776    {
777        parent = XtParent (parent);
778    }
779
780    menuShellW = XtCreatePopupShell (SHELL_NAME, xmMenuShellWidgetClass,
781                                     parent, (ArgList) args, i);
782
783    /*
784     * Create a RowColumn widget as a child of the shell for the menu pane.
785     * If the menu pane is top-level, create a popup menu for it and attach
786     *   the unmap callback to it.
787     * Otherwise, create a pulldown menu for it.
788     */
789
790    i = 0;
791    XtSetArg (args[i], XmNborderWidth, (XtArgVal) 0); i++;
792    XtSetArg (args[i], XmNwhichButton, (XtArgVal) SELECT_BUTTON); i++;
793    XtSetArg (args[i], XmNadjustMargin, (XtArgVal) TRUE); i++;
794
795    if (fTopLevelPane)
796    {
797        XtSetArg (args[i], XmNrowColumnType, (XtArgVal) XmMENU_POPUP); i++;
798        XtSetArg (args[i], XmNpopupEnabled, (XtArgVal) TRUE); i++;
799        menuW = XtCreateWidget (menuName, xmRowColumnWidgetClass, menuShellW,
800                                (ArgList) args, i);
801        XtAddCallback (menuW, XmNunmapCallback, (XtCallbackProc)UnmapCallback,
802                                (XtPointer) menuSpec);
803    }
804    else
805    {
806        XtSetArg (args[i], XmNrowColumnType, (XtArgVal) XmMENU_PULLDOWN); i++;
807        menuW = XtCreateWidget (menuName, xmRowColumnWidgetClass, menuShellW,
808                                (ArgList) args, i);
809    }
810
811    /*
812     * Create the specified menu entries as children of the menupane.
813     * Menus may contain the following widgets:
814     *
815     *   Label
816     *   Separator
817     *   CascadeButton
818     *   PushButton
819     *
820     * Add separator gadgets around menu titles.
821     */
822
823    XtSetArg (sepArgs[0], XmNseparatorType, (XtArgVal) XmDOUBLE_LINE);
824
825    n = 0;
826    menuItem = menuSpec->menuItems;
827    if ((menuItem == NULL) && (moreMenuItems != NULL))
828    /* handle custom menu with empty standard specification */
829    {
830        menuSpec->menuItems = menuItem = moreMenuItems;
831        moreMenuItems = NULL;
832    }
833    while (menuItem)
834    {
835        i = 0;
836
837        if (menuItem->wmFunction == F_Separator)
838        /*
839         * Add a Separator gadget for a menu separator.
840         * An immediately following title will not have a top separator.
841         */
842        {
843            children[n] =
844                XmCreateSeparatorGadget (menuW, SEPARATOR_NAME,
845                                (ArgList)NULL, 0);
846
847            fUseTitleSep = FALSE;
848        } /* F_Separator */
849
850        else
851        /*
852         * We will use one of:
853         *
854         *   Label
855         *   CascadeButton
856         *   PushButton
857         */
858        {
859            /*
860             * Construct the label
861             */
862            if ((menuItem->labelType == XmPIXMAP) &&
863                 (labelPixmap =
864                      MakeCachedLabelPixmap (pSD, menuW,
865                                             menuItem->labelBitmapIndex)))
866            {
867                XtSetArg (args[i], XmNlabelType, (XtArgVal) XmPIXMAP); i++;
868                XtSetArg (args[i], XmNlabelPixmap, (XtArgVal) labelPixmap); i++;
869                XtSetArg (args[i], XmNlabelInsensitivePixmap,
870                          (XtArgVal) labelPixmap); i++;
871            }
872            else
873            {
874                XtSetArg (args[i], XmNlabelType, (XtArgVal) XmSTRING); i++;
875                XtSetArg (args[i], XmNlabelString, (XtArgVal)
876                          (tmpstr = XmStringLtoRCreate(menuItem->label,
877                                            XmFONTLIST_DEFAULT_TAG))); i++;
878                sPtr = (StrList *) XtMalloc(sizeof(StrList));
879                if (sPtr == NULL)
880                  {
881                     MWarning ("Insufficient memory for menu %s\n",
882                               menuName);
883                     return (NULL);
884                  }
885                else
886                  {
887                     sPtr->string  = tmpstr;
888                     sPtr->next    = stringsToFree;
889                     stringsToFree = sPtr;
890                  }
891            }
892
893            if (menuItem->wmFunction == F_Title)
894            /*
895             * Add a centered Label gadget for a menu title.
896             * Include separators above and below the title.
897             * Don't include the top one if the title is the first pane item
898             *   or immediately follows a user-supplied separator.
899             */
900            {
901                if (fUseTitleSep)
902                {
903                    children[n] =
904                        XmCreateSeparatorGadget (menuW, SEPARATOR_NAME,
905                                                 sepArgs, 1); n++;
906                }
907
908                XtSetArg (args[i], XmNalignment, XmALIGNMENT_CENTER); i++;
909                children[n] = XmCreateLabelGadget (menuW, TITLE_NAME,
910                                                   (ArgList) args, i); n++;
911                children[n] = XmCreateSeparatorGadget (menuW, SEPARATOR_NAME,
912                                          sepArgs, 1);
913
914                /*
915                 * A following title will have both separators.
916                 */
917
918                fUseTitleSep = TRUE;
919            }
920
921            else
922            /*
923             * We will use one of:
924             *
925             *   CascadeButton
926             *   PushButton
927             *
928             * Both support mnemonics; only PushButtons support accelerators.
929             */
930            {
931                /*
932                 * Align text on the left.
933                 * Set any mnemonic text.
934                 */
935                XtSetArg (args[i], XmNalignment, XmALIGNMENT_BEGINNING); i++;
936
937                if (menuItem->mnemonic)
938                {
939                    XtSetArg (args[i], XmNmnemonic,
940                               (XtArgVal) menuItem->mnemonic); i++;
941                }
942
943                if (menuItem->wmFunction == F_Menu)
944                /*
945                 * Create a PopupShell and PulldownMenu for a submenu (the
946                 *   menushells are linked together).
947                 * Create a CascadeButton Widget
948                 * The submenu widget is attached to the CascadeButton gadget
949                 *   using the subMenuId resource.
950                 * Make the CascadeButton insensitive if the submenu cannot be
951                 *   created.
952                 */
953                {
954                    subMenuW = CreateMenuWidget (pSD,
955                                                 menuItem->wmFuncArgs, menuW,
956                                                 FALSE, topMenuSpec,
957                                                 (MenuItem *)NULL);
958                    if (subMenuW)
959                    /*
960                     * Attach submenu to cascade button.
961                     */
962                    {
963                        XtSetArg (args[i], XmNsubMenuId, (XtArgVal) subMenuW);
964                            i++;
965                        children[n] = XmCreateCascadeButtonGadget (menuW,
966                                          CASCADE_BTN_NAME, (ArgList) args, i);
967                    }
968                    else
969                    /*
970                     * Unable to create submenupane: make the entry insensitive.
971                     */
972                    {
973                        children[n] = XmCreateCascadeButtonGadget (menuW,
974                                          CASCADE_BTN_NAME, (ArgList) args, i);
975                        XtSetSensitive (children[n], FALSE);
976                    }
977
978                    /*
979                     * A following title will have both separators.
980                     */
981
982                    fUseTitleSep = TRUE;
983                }
984
985                else
986                /*
987                 * Create a PushButton gadget.
988                 */
989                {
990                    /*
991                     * If an accelerator is specified, set acceleratorText,
992                     * then create an accelerator KeySpec and insert it at the
993                     * head of the toplevel MenuSpec's list.
994                     */
995                    if (menuItem->accelText)
996                    {
997                        XtSetArg (args[i], XmNacceleratorText, (XtArgVal)
998                                  (tmpstr = XmStringLtoRCreate(menuItem->accelText,
999                                                               XmFONTLIST_DEFAULT_TAG))); i++;
1000                        sPtr = (StrList *) XtMalloc(sizeof(StrList));
1001                        if (sPtr == NULL)
1002                          {
1003                             MWarning ("Insufficient memory for menu %s\n",
1004                                       menuName);
1005                             return (NULL);
1006                          }
1007                        else
1008                          {
1009                             sPtr->string = tmpstr;
1010                             sPtr->next   = stringsToFree;
1011                             stringsToFree = sPtr;
1012                          }
1013
1014                        if ((accelKeySpec = (KeySpec *)
1015                                 XtMalloc (sizeof (KeySpec ))) == NULL)
1016                        /* Handle insufficent memory */
1017                        {
1018                            MWarning ("Insufficient memory for menu %s\n",
1019                                      menuName);
1020                            menuSpec->currentContext &= ~CR_MENU_MARK;
1021                            return (NULL);
1022                        }
1023
1024                        accelKeySpec->state = menuItem->accelState;
1025                        accelKeySpec->keycode = menuItem->accelKeyCode;
1026                        accelKeySpec->context = topMenuSpec->accelContext;
1027                        accelKeySpec->subContext = 0;
1028                        accelKeySpec->wmFunction = menuItem->wmFunction;
1029                        accelKeySpec->wmFuncArgs = menuItem->wmFuncArgs;
1030                        accelKeySpec->nextKeySpec = topMenuSpec->accelKeySpecs;
1031                        topMenuSpec->accelKeySpecs = accelKeySpec;
1032                    }
1033
1034                    children[n] = XmCreatePushButtonGadget (menuW,
1035                                      PUSH_BTN_NAME, (ArgList) args, i);
1036
1037                    /*
1038                     * Set sensitivity.  Initially we only consider the context
1039                     * of the top level menupane.
1040                     */
1041
1042                    if (menuItem->greyedContext & topMenuSpec->currentContext)
1043                    /* insensitive button in this context*/
1044                    {
1045                        XtSetSensitive (children[n], FALSE);
1046                    }
1047                    else
1048                    /* sensitive button in this context*/
1049                    {
1050                        XtSetSensitive (children[n], TRUE);
1051                    }
1052
1053                    /*
1054                     * If necessary, fill a menuButtons element for this
1055                     * PushButton.  Malloc or Realloc the array if necessary.
1056                     */
1057                    if ((menuItem->greyedContext) || (menuItem->mgtMask))
1058                    {
1059                        if (!SavePBInfo (topMenuSpec, menuItem, children[n]))
1060                        {
1061                            MWarning("Insufficient memory for menu %s\n",
1062                                       menuName);
1063                            menuSpec->currentContext &= ~CR_MENU_MARK;
1064                            return (NULL);
1065                        }
1066                    }
1067
1068                    /*
1069                     * Set up the function callback.
1070                     * A following title will have both separators.
1071                     */
1072
1073                    XtAddCallback (children[n], XmNactivateCallback,
1074                            (XtCallbackProc)ActivateCallback,
1075                                   (XtPointer) menuItem);
1076
1077                    fUseTitleSep = TRUE;
1078                }
1079            }
1080        }
1081
1082        /*
1083         * Next menu item:  handle custom items and full children[].
1084         */
1085        n++;
1086        menuItem = menuItem->nextMenuItem;
1087        if ((menuItem == NULL) && (moreMenuItems != NULL))
1088        {
1089            menuSpec->menuItems = menuItem = moreMenuItems;
1090            moreMenuItems = NULL;
1091        }
1092        if (n >= CHILDREN_CACHE - 2)  /* leave room for title separators */
1093        {
1094            XtManageChildren (children, n);
1095            n = 0;
1096        }
1097    }
1098
1099    if (n > 0)
1100    {
1101        XtManageChildren (children, n);
1102    }
1103
1104    /*
1105     * Get the initial height of the top level menu pane shell.
1106     * The actual height will change according to clientFunctions.
1107     */
1108    if (fTopLevelPane)
1109    {
1110        i = 0;
1111        XtSetArg (args[i], XtNheight, &menuHeight);  i++;
1112        XtGetValues (menuW, (ArgList)args, i);
1113        topMenuSpec->height = (unsigned int) menuHeight;
1114    }
1115
1116
1117    /* free the string that may have been created earlier. */
1118    for (sPtr = stringsToFree; sPtr != NULL; )
1119      {
1120         stringsToFree = stringsToFree->next;
1121         XmStringFree(sPtr->string);
1122         sPtr = stringsToFree;
1123      }
1124
1125
1126    /* Unmark the menu specification and return. */
1127    menuSpec->currentContext &= ~CR_MENU_MARK;
1128    return (menuW);
1129
1130} /* END OF FUNCTION CreateMenuWidget */
1131
1132
1133
1134/*************************************<->*************************************
1135 *
1136 *  PostMenu (menuSpec, pCD, x, y, button, newContext, flags, passedInEvent)
1137 *
1138 *
1139 *  Description:
1140 *  -----------
1141 *  This function is used to post a menu at a particular location.
1142 *
1143 *
1144 *  Inputs:
1145 *  ------
1146 *  menuSpec =      menu specification
1147 *  pCD =           client data
1148 *  x,y =           position to post the menu if (flags & POST_AT_XY) set
1149 *  button =        button number posting the menu or NoButton (WmGlobal.h) if
1150 *                  posted by a key
1151 *  newContext =    context that the menu is to be posted under.
1152 *  flags =         POST_AT_XY bit set iff x,y are valid, else compute from pCD
1153 *                  POST_TRAVERSAL_ON bit set if set traversal on
1154 *
1155 *  Outputs:
1156 *  -------
1157 *  menuSpec =        menu specification with modifications
1158 *  wmGD.menuClient = pCD
1159 *  wmGD.menuActive = menuSpec
1160 *
1161 *
1162 *  Comments:
1163 *  --------
1164 *  Accepts x,y only if POST_AT_XY flag bit set.  Otherwise, computes from pCD.
1165 *  Adjusts PushButton sensitivity according to context and function type.
1166 *  Manages/Unmanages PushButtons according to clientFunction resource.
1167 *  Sets traversal on if button==NoButton or POST_TRAVERSAL_ON flag bit set.
1168 *
1169 *************************************<->***********************************/
1170
1171#ifdef _NO_PROTO
1172void PostMenu (menuSpec, pCD, x, y, button, newContext, flags, passedInEvent)
1173
1174    MenuSpec    *menuSpec;
1175    ClientData  *pCD;
1176    int          x, y;
1177    unsigned int button;
1178    Context      newContext;
1179    long         flags;
1180    XEvent       *passedInEvent;
1181   
1182#else /* _NO_PROTO */
1183void PostMenu (MenuSpec *menuSpec, ClientData *pCD, int x, int y, unsigned int button, Context newContext, long flags, XEvent *passedInEvent)
1184#endif /* _NO_PROTO */
1185{
1186    int              i;
1187    Arg              args[3];
1188    unsigned int     whichButton;
1189    Dimension        menuHeight;
1190    XButtonPressedEvent event;
1191    Window           saveWindow;
1192    int              saveType;
1193   
1194    if ((menuSpec == NULL) || (menuSpec->menuWidget == NULL))
1195    {
1196        return;
1197    }
1198
1199
1200    /*
1201     * Don't post a menu from an icon in the iconbox if the
1202     * icon is not visible
1203     */
1204    if((newContext == F_SUBCONTEXT_IB_WICON ||
1205       newContext == F_SUBCONTEXT_IB_IICON) &&
1206       (!(IconVisible(pCD))))
1207    {
1208        return;
1209    }
1210
1211    /*
1212     * Set grabContext to be used in GrabWin when no event is passed
1213     * to GrabWin.
1214     */
1215
1216    wmGD.grabContext = newContext;
1217
1218    /*
1219     *  Adjust PushButton sensitivity and manage/unmanage status.
1220     *  If the manage status of the system menu has changed,
1221     *  then get the height of the top level menu pane shell and
1222     *  cache it in its MenuSpec.
1223     */
1224   
1225
1226    if (AdjustPBs (menuSpec, pCD, newContext))
1227    {
1228        i = 0;
1229        XtSetArg (args[i], XtNheight, &menuHeight);  i++;
1230        XtGetValues (menuSpec->menuWidget, (ArgList)args, i);
1231        menuSpec->height = (unsigned int) menuHeight;
1232    }
1233    menuSpec->currentContext = newContext;
1234
1235    /*
1236     *  Adjust the whichButton resource if necessary.
1237     *  Use SELECT_BUTTON for NoButton.
1238     */
1239
1240    whichButton = (button == NoButton) ? SELECT_BUTTON : button;
1241    if (whichButton != menuSpec->whichButton)
1242    {
1243        i = 0;
1244        XtSetArg (args[i], XmNwhichButton, (XtArgVal) whichButton); i++;
1245        XtSetValues (menuSpec->menuWidget, args, i);
1246        menuSpec->whichButton = whichButton;
1247    }
1248
1249    /*
1250     *  Determine the position of the popup menu.
1251     *  Compute position if necessary (system menu).
1252     */
1253
1254    if (!(flags & POST_AT_XY))
1255    /* compute the position */
1256    {
1257        GetSystemMenuPosition (pCD, &x, &y, menuSpec->height, newContext);
1258    }
1259
1260    event.x_root = x;
1261    event.y_root = y;
1262    XmMenuPosition (menuSpec->menuWidget, &event);
1263
1264    wmGD.menuClient = pCD;
1265    wmGD.menuActive = menuSpec;   /* set to NULL within UnmapCallback() */
1266
1267    /*
1268     * Post the menu by managing its top-level RowColumn.
1269     *
1270     * First dispatch the event to set the time stamp in the toolkit
1271     */
1272
1273    if(passedInEvent)
1274    {
1275        saveWindow = passedInEvent->xany.window;
1276        passedInEvent->xany.window = 0;
1277        saveType = passedInEvent->type;
1278        passedInEvent->type = 0;
1279       
1280        XtDispatchEvent(passedInEvent);
1281        passedInEvent->xany.window = saveWindow;
1282        passedInEvent->type = saveType;
1283    }
1284   
1285#ifndef ALTERNATE_POSTMENU
1286
1287    XtManageChild (menuSpec->menuWidget);
1288
1289#else
1290    if (flags & POST_STICKY)
1291    {
1292        _XmSetPopupMenuClick(menuSpec->menuWidget, True);
1293    }
1294    else
1295    {
1296        _XmSetPopupMenuClick(menuSpec->menuWidget, False);
1297    }
1298
1299    /*
1300     * Post the menu by calling the convenience routine that verifies
1301     * the button event, updates the Xt timestamp, and finally manages
1302     * the pane.
1303     */
1304
1305    _XmPostPopupMenu( menuSpec->menuWidget, passedInEvent);
1306#endif
1307
1308#ifdef AUTOMATION
1309        SetMwmMenuWindow(pCD, menuSpec->menuWidget);
1310#endif
1311
1312    /*
1313     *  set the traversal state.
1314     */
1315
1316    if ((button == NoButton) || (flags & POST_TRAVERSAL_ON))
1317    /* turn traversal on */
1318    {
1319        TraversalOn (menuSpec);
1320    }
1321    else
1322    /* turn traversal off */
1323    {
1324        TraversalOff (menuSpec);
1325    }
1326
1327} /* END OF FUNCTION PostMenu */
1328
1329
1330
1331/*************************************<->*************************************
1332 *
1333 *  UnpostMenu (menuSpec)
1334 *
1335 *
1336 *  Description:
1337 *  -----------
1338 *  This function is used to unpost a menu.
1339 *
1340 *
1341 *  Inputs:
1342 *  ------
1343 *  menuSpec =      menu specification
1344 *
1345 *  Outputs:
1346 *  -------
1347 *  None.
1348 *
1349 *
1350 *  Comments:
1351 *  --------
1352 *  wmGD.menuActive and wmGD.menuUnpostKey are set to NULL within
1353 *  UnmapCallback.
1354 *
1355 *************************************<->***********************************/
1356
1357#ifdef _NO_PROTO
1358void UnpostMenu (menuSpec)
1359
1360    MenuSpec    *menuSpec;
1361#else /* _NO_PROTO */
1362void UnpostMenu (MenuSpec *menuSpec)
1363#endif /* _NO_PROTO */
1364{
1365    if (menuSpec && (menuSpec->menuWidget))
1366    /*
1367     * Unpost the menu by unmanaging its top-level RowColumn.
1368     */
1369    {
1370        XtUnmanageChild (menuSpec->menuWidget);
1371#ifndef OLD_COLORMAP
1372        ForceColormapFocus (ACTIVE_PSD, ACTIVE_PSD->colormapFocus);
1373#endif
1374    }
1375
1376} /* END OF FUNCTION UnpostMenu */
1377
1378
1379
1380/*************************************<->*************************************
1381 *
1382 *  ActivateCallback (w, client_data, call_data)
1383 *
1384 *
1385 *  Description:
1386 *  -----------
1387 *  This function is called whenever a menu item is selected.
1388 *
1389 *
1390 *  Inputs:
1391 *  ------
1392 *  w =               menubuttonWidget
1393 *  client_data =     pointer to menu button's MenuItem structure
1394 *  call_data =       not used
1395 *  wmGD.menuClient = pointer to client's ClientData structure
1396 *
1397 *
1398 *  Outputs:
1399 *  -------
1400 *  None.
1401 *
1402 *
1403 *  Comments:
1404 *  --------
1405 *  None.
1406 *
1407 *************************************<->***********************************/
1408
1409#ifdef _NO_PROTO
1410void ActivateCallback (w, client_data, call_data)
1411
1412    Widget  w;
1413    XtPointer client_data;
1414    XtPointer call_data;
1415#else /* _NO_PROTO */
1416void ActivateCallback (Widget w, XtPointer client_data, XtPointer call_data)
1417#endif /* _NO_PROTO */
1418{
1419    ((MenuItem *)client_data)->wmFunction (
1420                ((MenuItem *)client_data)->wmFuncArgs, wmGD.menuClient, NULL);
1421
1422} /* END OF FUNCTION ActivateCallback */
1423
1424
1425
1426/*************************************<->*************************************
1427 *
1428 *  UnmapCallback (w, client_data, call_data)
1429 *
1430 *
1431 *  Description:
1432 *  -----------
1433 *  This function is called whenever a toplevel RowColumn is unmapped.
1434 *
1435 *
1436 *  Inputs:
1437 *  ------
1438 *  w =
1439 *  client_data =       not used
1440 *  call_data =         not used
1441 *  wmGD.gadgetClient = last client with depressed client
1442 *
1443 *
1444 *  Outputs:
1445 *  -------
1446 *  wmGD.menuActive = NULL
1447 *  wmGD.menuUnpostKeySpec = NULL
1448 *  wmGD.checkHotspot = FALSE
1449 *
1450 *
1451 *  Comments:
1452 *  --------
1453 *  None.
1454 *
1455 *************************************<->***********************************/
1456
1457#ifdef _NO_PROTO
1458void UnmapCallback (w, client_data, call_data)
1459
1460    Widget  w;
1461    XtPointer client_data;
1462    XtPointer call_data;
1463#else /* _NO_PROTO */
1464void UnmapCallback (Widget w, XtPointer client_data, XtPointer call_data)
1465#endif /* _NO_PROTO */
1466{
1467    wmGD.menuActive = NULL;
1468    wmGD.menuUnpostKeySpec = NULL;
1469    wmGD.checkHotspot = FALSE;
1470
1471    if (wmGD.gadgetClient)
1472    {
1473        PopGadgetOut(wmGD.gadgetClient, FRAME_SYSTEM);
1474    }
1475
1476#ifndef OLD_COLORMAP
1477    ForceColormapFocus (ACTIVE_PSD, ACTIVE_PSD->colormapFocus);
1478#endif
1479    PullExposureEvents();
1480
1481} /* END OF FUNCTION UnmapCallback */
1482
1483
1484/*************************************<->*************************************
1485 *
1486 *  MWarning (message)
1487 *
1488 *
1489 *  Description:
1490 *  -----------
1491 *  This function lists a message to stderr.
1492 *
1493 *
1494 *  Inputs:
1495 *  ------
1496 *  format  = pointer to a format string
1497 *  message = pointer to a message string
1498 *
1499 *************************************<->***********************************/
1500
1501#ifdef _NO_PROTO
1502void MWarning (format, message)
1503
1504    char *format;
1505    char *message;
1506#else /* _NO_PROTO */
1507void MWarning (char *format, char *message)
1508#endif /* _NO_PROTO */
1509{
1510#define MAXPATH 1023
1511
1512    if (strlen(format) + strlen(message)  <  MAXPATH)
1513      {
1514         char pch[MAXPATH+1];
1515
1516         sprintf (pch, format, message);
1517         Warning (pch);
1518      }
1519
1520} /* END OF FUNCTION MWarning */
1521
1522
1523
1524/*************************************<->*************************************
1525 *
1526 *  TraversalOff (menuSpec)
1527 *
1528 *
1529 *  Description:
1530 *  -----------
1531 *  This function turns menu traversal off.
1532 *
1533 *
1534 *  Inputs:
1535 *  ------
1536 *  menuSpec = menu specification
1537 *
1538 *
1539 *  Outputs:
1540 *  -------
1541 *  None.
1542 *
1543 *
1544 *  Comments:
1545 *  --------
1546 *  None.
1547 *
1548 *************************************<->***********************************/
1549
1550#ifdef _NO_PROTO
1551void TraversalOff (menuSpec)
1552
1553    MenuSpec  *menuSpec;
1554#else /* _NO_PROTO */
1555void TraversalOff (MenuSpec *menuSpec)
1556#endif /* _NO_PROTO */
1557{
1558    if (menuSpec && (menuSpec->menuWidget))
1559    {
1560        /* function pointer */
1561        (*((XmRowColumnWidgetClass) XtClass (menuSpec->menuWidget))
1562                                       ->row_column_class.menuProcedures)
1563                /* argument list */
1564               (XmMENU_TRAVERSAL, menuSpec->menuWidget, False, NULL, NULL);
1565    }
1566
1567} /* END OF FUNCTION TraversalOff */
1568
1569
1570
1571/*************************************<->*************************************
1572 *
1573 *  TraversalOn (menuSpec)
1574 *
1575 *
1576 *  Description:
1577 *  -----------
1578 *  This function turns menu traversal on.
1579 *
1580 *
1581 *  Inputs:
1582 *  ------
1583 *  menuSpec = menu specification
1584 *
1585 *
1586 *  Outputs:
1587 *  -------
1588 *  None.
1589 *
1590 *
1591 *  Comments:
1592 *  --------
1593 *  None.
1594 *
1595 *************************************<->***********************************/
1596
1597#ifdef _NO_PROTO
1598void TraversalOn (menuSpec)
1599
1600    MenuSpec  *menuSpec;
1601#else /* _NO_PROTO */
1602void TraversalOn (MenuSpec *menuSpec)
1603#endif /* _NO_PROTO */
1604{
1605
1606    if (menuSpec && (menuSpec->menuWidget))
1607    {
1608        /* function pointer */
1609        (*((XmRowColumnWidgetClass) XtClass (menuSpec->menuWidget))
1610                                   ->row_column_class.menuProcedures)
1611                /*argument list */
1612               (XmMENU_TRAVERSAL, menuSpec->menuWidget, True, NULL, NULL);
1613    }
1614
1615} /* END OF FUNCTION TraversalOn */
1616
1617
1618
1619/*************************************<->*************************************
1620 *
1621 *  FreeCustomMenuSpec (menuSpec)
1622 *
1623 *
1624 *  Description:
1625 *  -----------
1626 *  This procedure destroys a custom MenuSpec structure and its associated
1627 *  menu widget, menuItems list, menuButtons array, and menu accelerator list.
1628 *
1629 *
1630 *  Inputs:
1631 *  ------
1632 *  menuSpec = MenuSpec structure
1633 *
1634 *
1635 *  Outputs:
1636 *  -------
1637 *  None.
1638 *
1639 *
1640 *  Comments:
1641 *  --------
1642 *  Assumes that a MenuSpec is custom iff its name is NULL.
1643 *
1644 *  Assumes that ParseWmFuncStr() has parsed a menu item's function
1645 *  argument only for F_Exec and F_Menu.  If it is used for other functions,
1646 *  be sure to include them here!
1647 *
1648 *************************************<->***********************************/
1649
1650#ifdef _NO_PROTO
1651void FreeCustomMenuSpec (menuSpec)
1652
1653    MenuSpec  *menuSpec;
1654#else /* _NO_PROTO */
1655void FreeCustomMenuSpec (MenuSpec *menuSpec)
1656#endif /* _NO_PROTO */
1657{
1658    MenuItem    *menuItem;
1659    MenuItem    *nextMenuItem;
1660    KeySpec     *accelKeySpec;
1661    KeySpec     *nextAccelKeySpec;
1662
1663    if ((menuSpec == NULL) || (menuSpec->name != NULL))
1664    /* we only destroy custom menus! */
1665    {
1666        return;
1667    }
1668 
1669    /*
1670     * Fix for CR 5450 - If the custom menu is the same as wmGD.menuActive, call
1671     *                   the UnmapCallback directly to clean things up.  Since
1672     *                   the menu is going to be destroyed, this callback will
1673     *                   not get called, leaving MWM in a failure state.
1674     */
1675     if (wmGD.menuActive == menuSpec)
1676       UnmapCallback((Widget)NULL, (caddr_t)NULL, (caddr_t)NULL);
1677    /*
1678     * End fix for CR 5450
1679     */
1680 
1681    menuItem = menuSpec->menuItems;
1682    while (menuItem)
1683    {
1684        nextMenuItem = menuItem->nextMenuItem;
1685        FreeMenuItem (menuItem);
1686        menuItem = nextMenuItem;
1687    }
1688
1689    if (menuSpec->menuButtons)
1690    {
1691        XtFree ((char *)menuSpec->menuButtons);
1692    }
1693
1694    accelKeySpec = menuSpec->accelKeySpecs;
1695    while (accelKeySpec)
1696    {
1697        nextAccelKeySpec = accelKeySpec->nextKeySpec;
1698        XtFree ((char *)accelKeySpec);
1699        accelKeySpec = nextAccelKeySpec;
1700    }
1701
1702    if (menuSpec->menuWidget)
1703    /* destroy all children of the menu's MenuShell parent */
1704    {
1705        XtDestroyWidget (XtParent(menuSpec->menuWidget));
1706    }
1707
1708    XtFree ((char *)menuSpec);
1709
1710} /* END OF FUNCTION FreeCustomMenuSpec */
1711
1712
1713#ifdef AUTOMATION
1714#ifdef _NO_PROTO
1715static void SetMwmMenuInfo (pCD, menuSpec)
1716ClientData   *pCD;
1717MenuSpec     *menuSpec;
1718
1719#else
1720static void SetMwmMenuInfo (ClientData *pCD, MenuSpec *menuSpec)
1721#endif /* _NO_PROTO */
1722{
1723
1724    PropMwmFrameIconInfo    FrameIconProp;
1725    char                    *RetData;
1726    Atom                    FrameIconAtom, NewType;
1727    int                     NewFormat;
1728    unsigned long           NewNitems, NewBytesAfter;
1729    int                     SensitiveCount;
1730    MenuInfo                *NewMenuInfo;
1731    MenuButton              *NewMenuButton;
1732    MenuItem                *NewMenuItem;
1733    unsigned int            n;
1734    int                     status;
1735
1736
1737        RetData = NULL;
1738
1739    if (pCD == NULL || menuSpec == NULL)
1740        return;
1741
1742    FrameIconAtom = XmInternAtom(DISPLAY, _XA_MOTIF_WM_FRAME_ICON_INFO, False);
1743    status = XGetWindowProperty(DISPLAY, pCD->client, FrameIconAtom, 0L,
1744                                PROP_MWM_FRAME_ICON_INFO_ELEMENTS, False,
1745                                AnyPropertyType, &NewType, &NewFormat,
1746                                &NewNitems, &NewBytesAfter,
1747                                (unsigned char **)&RetData);
1748        if (status != Success || RetData == NULL)
1749        {
1750                /* Need a warning here; waiting for general warning handling code */
1751                return;
1752        }
1753
1754    bcopy((char *)RetData, (char *)&FrameIconProp,
1755          PROP_MWM_FRAME_ICON_INFO_ELEMENTS);
1756    /* Swap bytes if necessary */
1757    AutoSwapBytes(&FrameIconProp);
1758
1759    FrameIconProp.menuItemCount = 0;
1760    FrameIconProp.sensitiveItemCount = 0;
1761
1762    FrameIconProp.menuItemCount = menuSpec->menuButtonCount;
1763    NewMenuInfo = &FrameIconProp.windowMenu[0];
1764    for (n = 0; n < FrameIconProp.menuItemCount; n++)
1765        {
1766
1767        NewMenuInfo->item_name[0] = '\0';
1768        NewMenuInfo->sensitive = FALSE;
1769        NewMenuInfo++;
1770
1771    }
1772
1773    NewMenuInfo = &FrameIconProp.windowMenu[0];
1774    SensitiveCount = 0;
1775
1776    for (n = 0, NewMenuButton = menuSpec->menuButtons;
1777         n < menuSpec->menuButtonCount;
1778         n++, NewMenuButton++)
1779    {
1780
1781        if (NewMenuButton->managed == FALSE)
1782            continue;
1783
1784        NewMenuItem = NewMenuButton->menuItem;
1785        strcpy(NewMenuInfo->item_name, NewMenuItem->label);
1786        NewMenuInfo->sensitive = NewMenuButton->buttonWidget->core.sensitive;
1787        NewMenuInfo->item_y = NewMenuButton->buttonWidget->core.y +
1788                            (NewMenuButton->buttonWidget->core.height / 2);
1789        if (NewMenuInfo->sensitive == TRUE)
1790            SensitiveCount++;
1791        NewMenuInfo++;
1792
1793    }
1794
1795    FrameIconProp.byte_order = AutoByteOrderChar;
1796    FrameIconProp.sensitiveItemCount = SensitiveCount;
1797    XChangeProperty(DISPLAY, pCD->client, wmGD.xa_MWM_FRAME_ICON_INFO,
1798                    wmGD.xa_MWM_FRAME_ICON_INFO, 8, PropModeReplace,
1799                    (unsigned char *)&FrameIconProp,
1800                    PROP_MWM_FRAME_ICON_INFO_ELEMENTS);
1801    XSync(DISPLAY, False);
1802
1803    if (RetData != NULL)
1804        XFree((char *)RetData);
1805
1806} /* SetMwmMenuInfo */
1807
1808
1809#ifdef _NO_PROTO
1810static void SetMwmMenuWindow (pCD, menuWidget)
1811ClientData *pCD;
1812Widget     menuWidget;
1813
1814#else
1815static void SetMwmMenuWindow (ClientData *pCD, Widget menuWidget)
1816#endif /* _NO_PROTO */
1817{
1818
1819    PropMwmFrameIconInfo    FrameIconProp;
1820    char                    *RetData;
1821    Atom                    FrameIconAtom, NewType;
1822    int                     NewFormat;
1823    unsigned long           NewNitems, NewBytesAfter;
1824    Window                  MenuWin;
1825    int                     status;
1826
1827    if (pCD == NULL)
1828        return;
1829
1830    MenuWin = XtWindow(menuWidget);
1831
1832    FrameIconAtom = XmInternAtom(DISPLAY, _XA_MOTIF_WM_FRAME_ICON_INFO, False);
1833    status = XGetWindowProperty(DISPLAY, pCD->client, FrameIconAtom, 0L,
1834                                PROP_MWM_FRAME_ICON_INFO_ELEMENTS, False,
1835                                AnyPropertyType, &NewType, &NewFormat,
1836                                &NewNitems, &NewBytesAfter,
1837                                (unsigned char **)&RetData);
1838        if (status != Success || RetData == NULL)
1839        {
1840                /* Need a warning here; waiting for general warning handling code */
1841                return;
1842        }
1843
1844    bcopy((char *)RetData, (char *)&FrameIconProp,
1845          PROP_MWM_FRAME_ICON_INFO_ELEMENTS);
1846    /* Swap bytes if necessary */
1847    AutoSwapBytes(&FrameIconProp);
1848
1849    FrameIconProp.byte_order = AutoByteOrderChar;
1850    FrameIconProp.menuWin = MenuWin;
1851    XChangeProperty(DISPLAY, pCD->client, wmGD.xa_MWM_FRAME_ICON_INFO,
1852                    wmGD.xa_MWM_FRAME_ICON_INFO, 8, PropModeReplace,
1853                    (unsigned char *)&FrameIconProp,
1854                    PROP_MWM_FRAME_ICON_INFO_ELEMENTS);
1855    XSync(DISPLAY, False);
1856
1857    if (RetData != NULL)
1858        XFree((char *)RetData);
1859
1860    return;
1861
1862} /* SetMwmMenuWindow */
1863
1864#endif /* AUTOMATION */
Note: See TracBrowser for help on using the repository browser.