home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / src / Menu.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  24.1 KB  |  1,044 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /* 
  19.    Menu.cpp -- implementation file for Menu
  20.    Created: Chris Toshok <toshok@netscape.com>, 7-Aug-96.
  21.  */
  22.  
  23.  
  24.  
  25. #if DEBUG_toshok_
  26. #define D(x) x
  27. #else
  28. #define D(x)
  29. #endif
  30.  
  31. #include "xp_core.h"
  32. #include "prefapi.h"
  33.  
  34. #include "Menu.h"
  35. #include "Frame.h"
  36. #include "View.h"
  37. #include "Command.h"
  38. #include "RadioGroup.h"
  39. #include <Xm/XmP.h>
  40. #include <Xm/RowColumn.h>
  41. #include <Xm/CascadeBG.h>
  42. #include <Xm/PushBG.h>
  43. #include <Xm/LabelG.h>
  44. #include <Xm/ToggleB.h>
  45. #include <Xm/SeparatoG.h>
  46.  
  47. #include <Xfe/Xfe.h>
  48. #include <Xfe/BmCascade.h>
  49.  
  50.  
  51. // Check the class of a menu item
  52. #define IS_LABEL(w)        (XmIsLabel(w) || XmIsLabelGadget(w))
  53. #define IS_SEP(w)        (XmIsSeparator(w) || XmIsSeparatorGadget(w))
  54. #define IS_CASCADE(w)    (XmIsCascadeButton(w) || XmIsCascadeButtonGadget(w))
  55. #define IS_PUSH(w)        (XmIsPushButton(w) || XmIsPushButtonGadget(w))
  56. #define IS_TOGGLE(w)    (XmIsToggleButton(w) || XmIsToggleButtonGadget(w))
  57.  
  58. // Possible menu item classes
  59. #define ITEM_CASCADE_CLASS            xmCascadeButtonWidgetClass
  60. #define ITEM_FANCY_CASCADE_CLASS    xfeBmCascadeWidgetClass
  61. #define ITEM_LABEL_CLASS            xmLabelGadgetClass
  62. #define ITEM_PUSH_CLASS                xmPushButtonWidgetClass
  63. #define ITEM_SEP_CLASS                xmSeparatorGadgetClass
  64. #define ITEM_TOGGLE_CLASS            xmToggleButtonWidgetClass
  65.  
  66. XFE_Menu::XFE_Menu(XFE_Frame *parent_frame, MenuSpec *spec, Widget baseMenuWidget) 
  67.   : XFE_Component(parent_frame)
  68. {
  69. D(    printf ("in XFE_Menu::XFE_Menu()\n");)
  70.  
  71.   m_parentFrame = parent_frame;
  72.  
  73.   m_spec = NULL;
  74.  
  75.   if (baseMenuWidget)
  76.   {
  77.       setBaseWidget(baseMenuWidget);
  78.   }
  79.  
  80.   if (spec)
  81.   {
  82.       setMenuSpec(spec);
  83.   }
  84.  
  85.   m_parentFrame->registerInterest(XFE_View::chromeNeedsUpdating,
  86.                   this,
  87.                   (XFE_FunctionNotification)update_cb);
  88.  
  89.   m_parentFrame->registerInterest(XFE_View::commandNeedsUpdating,
  90.                   this,
  91.                   (XFE_FunctionNotification)updateCommand_cb);
  92.  
  93. D(    printf ("leaving XFE_Menu::XFE_Menu()\n");)
  94. }
  95.  
  96. XFE_Menu::~XFE_Menu()
  97. {
  98.   m_parentFrame->unregisterInterest(XFE_View::chromeNeedsUpdating,
  99.                     this,
  100.                     (XFE_FunctionNotification)update_cb);
  101.  
  102.   m_parentFrame->unregisterInterest(XFE_View::commandNeedsUpdating,
  103.                     this,
  104.                     (XFE_FunctionNotification)updateCommand_cb);
  105. }
  106.  
  107. XFE_CALLBACK_DEFN(XFE_Menu, update)(XFE_NotificationCenter */*obj*/, 
  108.                        void */*clientData*/, 
  109.                        void */*callData*/)
  110. {
  111.   update();
  112. }
  113.  
  114. void
  115. XFE_Menu::update()
  116. {
  117. D(    printf ("in XFE_Menu::update()\n");)
  118.   int num_children, i;
  119.   Widget *children;
  120.   
  121.   XtVaGetValues(m_widget,
  122.         XmNchildren, &children,
  123.         XmNnumChildren, &num_children,
  124.         NULL);
  125.   
  126.   for (i = 0; i < num_children; i ++)
  127.     updateMenuItem(children[i]);    
  128.  
  129. D(    printf ("leaving XFE_Menu::update()\n");)
  130. }
  131.  
  132. void
  133. XFE_Menu::updateSubMenu(Widget submenu)
  134. {
  135. D(    printf ("in XFE_Menu::updateSubMenu()\n");)
  136.   int num_children, i;
  137.   Widget *children;
  138.   
  139.   XtVaGetValues(submenu,
  140.         XmNchildren, &children,
  141.         XmNnumChildren, &num_children,
  142.         NULL);
  143.   
  144.   for (i = 0; i < num_children; i ++)
  145.     updateMenuItem(children[i]);
  146.  
  147. D(    printf ("leaving XFE_Menu::updateSubMenu()\n");)
  148. }
  149.  
  150. static char*
  151. menuItemGetCmdName(Widget w)
  152. {
  153.     XtPointer userData;
  154.  
  155.     XtVaGetValues(w,
  156.                   XmNuserData, &userData,
  157.                   NULL);
  158.     MenuSpec* spec = (MenuSpec*)userData;
  159.     
  160.     return spec ? spec->getCmdName() : "";
  161. }
  162.  
  163. void
  164. XFE_Menu::updateMenuItem(Widget menuItem)
  165. {
  166.   char *command_string;
  167.   XtPointer userData;
  168.   CommandType cmd;
  169.  
  170.   XtVaGetValues(menuItem,
  171.         XmNuserData, &userData,
  172.         NULL);
  173.  
  174.   MenuSpec* spec = (MenuSpec*)userData;
  175.   char**    params = (spec != NULL)? spec->cmd_args: (char**)NULL;
  176.   XFE_CommandInfo info(XFE_COMMAND_BUTTON_ACTIVATE,
  177.                        menuItem, NULL, params);
  178.  
  179.  
  180.   if (spec)
  181.       {
  182.           info.params = spec->cmd_args;
  183.  
  184.           cmd = spec->getCmdName();
  185.           
  186.           D(    printf ("in XFE_Menu::updateMenuItem(%s)\n", Command::getString(cmd));)
  187.               
  188.               command_string = m_parentFrame->commandToString(cmd,
  189.                                                               spec->callData,
  190.                                                               &info);
  191.               
  192.               if ( command_string )
  193.                   {
  194.                       XmString str;
  195.                       
  196.                       D(    printf ("    command string is %s\n", command_string);)
  197.                           
  198.                           str = XmStringCreate(command_string, XmFONTLIST_DEFAULT_TAG);
  199.                           
  200.                           XtVaSetValues(menuItem, XmNlabelString, str, NULL);
  201.                           
  202.                           XmStringFree(str);
  203.                   }
  204.       }
  205.   else
  206.       {
  207.           cmd = Command::intern(XtName(menuItem));
  208.       }
  209.  
  210.   /* if it's a cascade button, sensitize it's submenu. */
  211.   if (IS_CASCADE(menuItem))
  212.       {
  213.           Widget submenu = NULL;
  214.           
  215.           XtVaGetValues(menuItem,
  216.                         XmNsubMenuId, &submenu,
  217.                         NULL);
  218.           
  219.           if (submenu)
  220.               {
  221.                     if (XfeIsViewable(submenu)) 
  222.                       updateSubMenu(submenu);
  223.               }
  224.       }
  225.   else if (XmIsToggleButton(menuItem) )
  226.       {
  227.           Boolean turnOn;
  228.  
  229.           if (spec)
  230.               {
  231.                   turnOn = m_parentFrame->isCommandSelected(cmd, spec->callData,
  232.                                                             &info);
  233.               }
  234.           else
  235.               {
  236.                   turnOn = m_parentFrame->isCommandSelected(cmd);
  237.               }
  238.           
  239.           XmToggleButtonSetState(menuItem, turnOn, False);
  240.       }
  241.   else if (XmIsToggleButtonGadget(menuItem))
  242.       {
  243.           Boolean turnOn;
  244.  
  245.           if (spec)
  246.               {
  247.                   turnOn = m_parentFrame->isCommandSelected(cmd, spec->callData,
  248.                                                             &info);
  249.               }
  250.           else
  251.               {
  252.                   turnOn = m_parentFrame->isCommandSelected(cmd);
  253.               }
  254.  
  255.           XmToggleButtonGadgetSetState(menuItem, turnOn, False);
  256.       }
  257.   
  258.   /* we don't sensitize labels or cascadebuttons. */
  259.   if (IS_PUSH(menuItem) || IS_TOGGLE(menuItem))
  260.       {
  261.           Boolean isSensitive;
  262.  
  263.           if (spec)
  264.               {
  265.                   isSensitive = (m_parentFrame->handlesCommand(cmd, spec->callData, &info)
  266.                                  && m_parentFrame->isCommandEnabled(cmd, spec->callData, &info));
  267.               }
  268.           else
  269.               {
  270.                   isSensitive = (m_parentFrame->handlesCommand(cmd)
  271.                                  && m_parentFrame->isCommandEnabled(cmd,NULL,&info));
  272.               }
  273.  
  274.           XtVaSetValues(menuItem,
  275.                         XmNsensitive, isSensitive,
  276.                         NULL);
  277.       }
  278.   
  279. D(    printf ("leaving XFE_Menu::updateMenuItem()\n");)
  280. }
  281.  
  282. XFE_CALLBACK_DEFN(XFE_Menu, updateCommand)(XFE_NotificationCenter */*obj*/, 
  283.                           void */*clientData*/, 
  284.                           void *callData)
  285. {
  286. D(    printf ("in XFE_Menu::updateCommand()\n");)
  287.     int num_children, i;
  288.     Widget *children;
  289.     CommandType command = (CommandType)callData;
  290.     
  291.     XtVaGetValues(m_widget,
  292.                   XmNchildren, &children,
  293.                   XmNnumChildren, &num_children,
  294.                   NULL);
  295.     
  296.     for (i = 0; i < num_children; i ++)
  297.         {
  298.             if (IS_CASCADE(children[i]))
  299.                 {
  300.                     Widget submenu = NULL;
  301.                     
  302.                     XtVaGetValues(children[i],
  303.                                   XmNsubMenuId, &submenu,
  304.                                   NULL);
  305.                     
  306.                     if (submenu)
  307.                         {
  308.                             // Instead of checking if the pulldown menu shell is popped or not,
  309.                             // we should be checking if the submenu rowcolumn is mapped or not.
  310.                             
  311.                             // The reason is because all of the pulldown submenus sharing the
  312.                             // same popup shell; therefore, checking if the shell is managed
  313.                             // or not does not work. That's why our pulldown menu are generated
  314.                             // everytinge EnableClicking happens. - Thanks ramiro giving us
  315.                             // this wonderful API to test on our submenu.
  316.                             
  317.                             // This fix will prevent unnecessary submenu being created at the wrong
  318.                             // time.
  319.                             if (XfeIsViewable(submenu)) 
  320.                                 updateCommandInSubMenu(command, submenu);
  321.                         }
  322.                 }
  323.         }
  324.  
  325. D(    printf ("leaving XFE_Menu::updateCommand()\n");)
  326. }
  327.  
  328. void
  329. XFE_Menu::updateCommandInSubMenu(CommandType command,
  330.                     Widget submenu)
  331. {
  332. D(    printf ("in XFE_Menu::updateCommandInSubMenu()\n");)
  333.   int num_children, i;
  334.   Widget *children;
  335.   
  336.   XtVaGetValues(submenu,
  337.         XmNchildren, &children,
  338.         XmNnumChildren, &num_children,
  339.         NULL);
  340.   
  341.   for (i = 0; i < num_children; i ++)
  342.     updateCommandInMenuItem(command, children[i]);
  343.  
  344. D(    printf ("leaving XFE_Menu::updateCommandInSubMenu()\n");)
  345. }
  346.  
  347. void
  348. XFE_Menu::updateCommandInMenuItem(CommandType command, Widget menuItem)
  349. {
  350.   XtPointer userData;
  351.  
  352. D(    printf ("in XFE_Menu::updateCommandInMenuItem()\n");)
  353.   
  354.   XtVaGetValues(menuItem,
  355.         XmNuserData, &userData,
  356.         NULL);
  357.  
  358.   MenuSpec* spec = (MenuSpec*)userData;
  359.   CommandType cmd;
  360.  
  361.   XFE_CommandInfo info(XFE_COMMAND_BUTTON_ACTIVATE,
  362.                        menuItem, NULL);
  363.  
  364.  
  365.   if (spec)
  366.       {
  367.           info.params = spec->cmd_args;
  368.  
  369.           cmd = spec->getCmdName();
  370.       }
  371.   else
  372.       {
  373.           cmd = Command::intern(XtName(menuItem));
  374.       }
  375.  
  376.   if (command == cmd) 
  377.       {
  378.           Boolean isSensitive;
  379.  
  380.           if (spec)
  381.               {
  382.                   isSensitive = m_parentFrame->isCommandEnabled(cmd, spec->callData, &info);
  383.               }
  384.           else
  385.               {
  386.                   isSensitive = m_parentFrame->isCommandEnabled(cmd,NULL,&info);
  387.               }
  388.  
  389.           XtVaSetValues(menuItem,
  390.                         XmNsensitive, isSensitive,
  391.                         0);
  392.       }
  393.  
  394.   /* if it's a cascade button, also sensitize it's submenu. */
  395.   if (IS_CASCADE(menuItem))
  396.       {
  397.           Widget submenu = NULL;
  398.           
  399.           XtVaGetValues(menuItem,
  400.                         XmNsubMenuId, &submenu,
  401.                         NULL);
  402.           
  403.           if (submenu)
  404.               {
  405.                   if (XfeIsViewable(submenu)) 
  406.                       updateCommandInSubMenu(command, submenu);
  407.               }
  408.       }
  409. D(    printf ("leaving XFE_Menu::updateCommandInMenuItem()\n");)
  410. }
  411.  
  412. Widget
  413. XFE_Menu::createPulldown(char *cascadeName, MenuSpec *, Widget parent_menu, 
  414.                          XP_Bool is_fancy)
  415. {
  416.     Widget cascade, pulldown;
  417.     Arg av[10];
  418.     int ac;
  419.     Visual *v = 0;
  420.     Colormap cmap = 0;
  421.     Cardinal depth = 0;
  422.     WidgetClass wc = is_fancy ? ITEM_FANCY_CASCADE_CLASS : ITEM_CASCADE_CLASS;
  423.  
  424.     XtVaGetValues(m_parentFrame->getBaseWidget(),
  425.                   XtNvisual, &v, 
  426.                   XtNcolormap, &cmap,
  427.                   XtNdepth, &depth, 
  428.                   0);
  429.     
  430.     ac = 0;
  431.     XtSetArg(av[ac], XmNvisual, v); ac++;
  432.     XtSetArg(av[ac], XmNcolormap, cmap); ac++;
  433.     XtSetArg(av[ac], XmNdepth, depth); ac++;
  434.     
  435.     pulldown = XmCreatePulldownMenu(parent_menu,
  436.                                     "pulldown",
  437.                                     av, ac);
  438.     
  439.     cascade = XtVaCreateWidget(cascadeName,
  440.                                wc,
  441.                                parent_menu,
  442.                                XmNsubMenuId, pulldown,
  443.                                NULL);
  444.     
  445. #if DELAYED_MENU_CREATION
  446.     XtAddCallback(cascade, XmNcascadingCallback, delayed_create_pulldown, this);
  447. #else
  448.     if (spec)
  449.         {
  450.             MenuSpec *cur_spec;
  451.             Widget items[150];
  452.             int num_items = 0;
  453.  
  454.             cur_spec = spec;
  455.             while (cur_spec->menuItemName)
  456.                 {
  457.                     items[num_items] = createMenuItem(cur_spec, cascade, pulldown);
  458.  
  459.                     if (items[num_items] != NULL) // we return NULL for DYNA_MENUITEMS
  460.                         num_items++;
  461.                     
  462.                     cur_spec ++;
  463.                 }
  464.  
  465.             if (num_items)
  466.                 XtManageChildren(items, num_items);
  467.         }
  468. #endif
  469.     return cascade;
  470. }
  471.  
  472. Widget
  473. XFE_Menu::createMenuItem(MenuSpec *spec, Widget parent_cascade, Widget parent)
  474. {
  475.     Widget result = 0;
  476.     
  477.     switch(spec->tag)
  478.         {
  479.         case LABEL:
  480.             {
  481.                 result = XtCreateWidget(spec->menuItemName,
  482.                                         ITEM_LABEL_CLASS,
  483.                                         parent,
  484.                                         NULL, 0);
  485.                 break;
  486.             };
  487.         case SEPARATOR:
  488.             {
  489.                 result = XtCreateWidget(spec->menuItemName,
  490.                                         ITEM_SEP_CLASS,
  491.                                         parent,
  492.                                         NULL, 0);
  493.                 break;
  494.             }
  495.         case PUSHBUTTON:
  496.             {
  497.                 result = XtCreateWidget(spec->menuItemName,
  498.                                         ITEM_PUSH_CLASS,
  499.                                         parent,
  500.                                         NULL, 0);
  501.                 
  502.                 XtAddCallback(result, XmNarmCallback, pushb_arm_cb, this);
  503.                 XtAddCallback(result, XmNactivateCallback, pushb_activate_cb, this);
  504.                 XtAddCallback(result, XmNdisarmCallback, pushb_disarm_cb, this);
  505.                 
  506.                 break;
  507.             }
  508.         case CUSTOMBUTTON:
  509.             {
  510.                 char* str;
  511.                 XmString xm_str;
  512.                 KeySym mnemonic;
  513.  
  514.                 if ( !PREF_GetLabelAndMnemonic((char*) spec->callData, &str, 
  515.                         &xm_str, &mnemonic) ) break;
  516.  
  517.                 if ( !strcmp(str, "-") ) {
  518.                     result = XtCreateWidget(spec->menuItemName,
  519.                                             ITEM_SEP_CLASS,
  520.                                             parent,
  521.                                             NULL, 0);
  522.                 } else {
  523.                 
  524.                     result = XtCreateWidget(spec->menuItemName,
  525.                                             ITEM_PUSH_CLASS,
  526.                                             parent,
  527.                                             NULL, 0);
  528.                 
  529.                     XtVaSetValues(result, XmNlabelString, xm_str, NULL);
  530.                     if ( mnemonic ) {
  531.                         XtVaSetValues(result, XmNmnemonic, mnemonic, NULL);
  532.                     }
  533.  
  534.                     XtAddCallback(result, XmNarmCallback, pushb_arm_cb, this);
  535.                     XtAddCallback(result, XmNactivateCallback, pushb_activate_cb, this);
  536.                     XtAddCallback(result, XmNdisarmCallback, pushb_disarm_cb, this);
  537.                 }
  538.                 
  539.                 XmStringFree(xm_str);
  540.  
  541.                 break;
  542.             }
  543.         case CASCADEBUTTON:
  544.         case FANCY_CASCADEBUTTON:
  545.             {
  546.                 result = createPulldown(spec->menuItemName,
  547.                                         spec->submenu,
  548.                                         parent,
  549.                                         spec->tag == FANCY_CASCADEBUTTON);
  550.                 
  551. #ifndef DELAYED_MENU_CREATION
  552.                 XtAddCallback(result, XmNcascadingCallback, cascade_update_cb, this);
  553. #endif
  554.                 
  555.                 break;
  556.             }
  557.         case TOGGLEBUTTON:
  558.             result = XtCreateWidget(spec->menuItemName,
  559.                                     ITEM_TOGGLE_CLASS,
  560.                                     parent,
  561.                                     NULL, 0);
  562.             
  563.             if (spec->radioGroupName) {
  564.                 XtAddCallback(result, XmNarmCallback, radiob_arm_cb, this);
  565.                 XtAddCallback(result, XmNvalueChangedCallback, radiob_activate_cb, this);
  566.                 XtAddCallback(result, XmNdisarmCallback, radiob_disarm_cb, this);
  567.                 
  568.                 XFE_RadioGroup *rg;
  569.                 rg = XFE_RadioGroup::getByName(spec->radioGroupName, m_parentFrame);
  570.                 rg->addChild(result);
  571.             } else {
  572.                 XtAddCallback(result, XmNarmCallback, toggleb_arm_cb, this);
  573.                 XtAddCallback(result, XmNvalueChangedCallback, toggleb_activate_cb,this);
  574.                 XtAddCallback(result, XmNdisarmCallback, toggleb_disarm_cb, this);
  575.             }
  576.             
  577.             break;
  578.         case DYNA_CASCADEBUTTON:
  579.         case DYNA_FANCY_CASCADEBUTTON:
  580.             XP_ASSERT(spec->submenu == NULL); // doesn't make sense if you have a submenu here...
  581.             
  582.             result = createPulldown(spec->menuItemName,
  583.                                     spec->submenu,
  584.                                     parent,
  585.                                     spec->tag == DYNA_FANCY_CASCADEBUTTON);
  586.             
  587.             (*spec->generateProc)(result, spec->callData, m_parentFrame);
  588.             break;
  589.             
  590.         case DYNA_MENUITEMS:
  591.             XP_ASSERT(XmIsRowColumn(parent));
  592.             
  593.             (*spec->generateProc)(parent_cascade, spec->callData, m_parentFrame);
  594.             break;
  595.         default:
  596.             XP_ASSERT(0);
  597.             break;
  598.         }
  599.     
  600.     if (result) {
  601.         XtVaSetValues(result,
  602.                       XmNuserData, spec,
  603.                       NULL);
  604.     }
  605.     
  606.     return result;
  607. }
  608.  
  609. void
  610. XFE_Menu::addMenuSpec(MenuSpec *spec)
  611. {
  612.   if (!m_spec)
  613.     setMenuSpec(spec);
  614.   else
  615.     createWidgets(spec);
  616. }
  617.  
  618. void
  619. XFE_Menu::createWidgets()
  620. {
  621.   createWidgets(m_spec);
  622. }
  623.  
  624. void
  625. XFE_Menu::createWidgets(MenuSpec *spec)
  626. {
  627.     MenuSpec *cur_spec;
  628.     Widget items[150];
  629.     int num_items = 0;
  630.  
  631. D(    printf ("in XFE_Menu::createWidgets()\n");)
  632.     if (!m_spec)
  633.         return;
  634.  
  635.     cur_spec = spec;
  636.     
  637.     while (cur_spec->menuItemName)
  638.         {
  639.             items[num_items] = createMenuItem(cur_spec, NULL, m_widget);
  640.             
  641.             if (items[num_items] != NULL) // we return NULL for DYNA_MENUITEMS
  642.                 {
  643.                     if (!strcmp(cur_spec->menuItemName, xfeMenuHelp)
  644.                         && IS_CASCADE(items[num_items]))
  645.                         XtVaSetValues(m_widget,
  646.                                       XmNmenuHelpWidget, items[num_items],
  647.                                       NULL);
  648.                     
  649.                     num_items++;
  650.                 }
  651.             cur_spec++;
  652.         }
  653.  
  654.     if (num_items)
  655.         XtManageChildren(items, num_items);
  656.  
  657. D(    printf ("leaving XFE_Menu::createWidgets()\n");)
  658. }
  659.  
  660. Widget
  661. XFE_Menu::addMenuItem(char *itemName,
  662.               EChromeTag tag,
  663.               MenuSpec* submenuspec,
  664.               char* radioGroupName,
  665.               Boolean toggleSet,
  666.               void *calldata,
  667.               dynamenuCreateProc generateProc,
  668.               int position)
  669. {
  670.   // This code sucks now.
  671.   // Using a temp spec doesn't work, because we try to reference
  672.   // it from the menu item's user data.
  673.   MenuSpec tmp_spec;
  674.   Widget item;
  675.  
  676.   tmp_spec.menuItemName = itemName;
  677.   tmp_spec.tag = tag;
  678.   tmp_spec.submenu = submenuspec;
  679.   tmp_spec.radioGroupName = radioGroupName;
  680.   tmp_spec.toggleSet = toggleSet;
  681.   tmp_spec.callData = calldata;
  682.   tmp_spec.generateProc = generateProc;
  683.  
  684.   item = createMenuItem(&tmp_spec, NULL, m_widget);
  685.  
  686.   XtVaSetValues(item,
  687.         XmNpositionIndex, position,
  688.         NULL);
  689.  
  690.   return item;
  691. }
  692.  
  693. void
  694. XFE_Menu::removeMenuItem(char */*menuName*/,
  695.                 EChromeTag /*tag*/)
  696. {
  697. }
  698.  
  699. Widget
  700. XFE_Menu::findMenuItemInMenu(char *menuName,
  701.                  EChromeTag tag,
  702.                  Widget menu)
  703. {
  704.   int num_children;
  705.   Widget *children;
  706.   int i;
  707.  
  708.   XtVaGetValues(menu,
  709.         XmNnumChildren, &num_children,
  710.         XmNchildren, &children,
  711.         NULL);
  712.  
  713.   for (i = 0; i < num_children; i ++)
  714.     {
  715.       Widget child = children[i];
  716.  
  717.       if (!strcmp(menuName, menuItemGetCmdName(child)))
  718.     {
  719.       switch (tag)
  720.         {
  721.         case LABEL:
  722.           if (IS_LABEL(child))
  723.         return child;
  724.           break;
  725.         case TOGGLEBUTTON:
  726.           if (IS_TOGGLE(child))
  727.         return child;
  728.           break;
  729.         case CASCADEBUTTON:
  730.           if (IS_CASCADE(child))
  731.         return child;
  732.           break;
  733.         case PUSHBUTTON:
  734.           if (IS_PUSH(child))
  735.         return child;
  736.           break;
  737.         case SEPARATOR:
  738.           if (IS_SEP(child))
  739.         return child;
  740.           break;
  741.         default:
  742.           XP_ASSERT(0);
  743.           break;
  744.         }
  745.     }
  746.       else
  747.     {
  748.       if (IS_CASCADE(child))
  749.         {
  750.           Widget submenu = NULL;
  751.           Widget submenu_child;
  752.  
  753.           XtVaGetValues(child,
  754.                 XmNsubMenuId, &submenu,
  755.                 NULL);
  756.  
  757.           submenu_child = findMenuItemInMenu(menuName, tag, submenu);
  758.  
  759.           if (submenu_child)
  760.         return submenu_child;
  761.         }
  762.     }
  763.     }
  764.  
  765.   return 0;
  766. }
  767.  
  768. Widget
  769. XFE_Menu::findMenuItem(char *menuName,
  770.                EChromeTag tag)
  771. {
  772.   return findMenuItemInMenu(menuName, tag, m_widget);
  773. }
  774.  
  775. void
  776. XFE_Menu::hideMenuItem(char *menuName,
  777.                EChromeTag tag)
  778. {
  779.   Widget item = findMenuItem(menuName,
  780.                  tag);
  781.  
  782.   if (item)
  783.     XtUnmanageChild(item);
  784. }
  785.  
  786. void
  787. XFE_Menu::showMenuItem(char *menuName,
  788.                EChromeTag tag)
  789. {
  790.   Widget item = findMenuItem(menuName,
  791.                  tag);
  792.  
  793.   if (item)
  794.     XtManageChild(item);
  795. }
  796.  
  797. void
  798. XFE_Menu::setMenuSpec(MenuSpec *menu_spec)
  799. {
  800. D(    printf ("in XFE_Menu::setMenuSpec()\n");)
  801.   XP_ASSERT(m_spec == NULL);
  802.  
  803.   m_spec = menu_spec;
  804.  
  805.   createWidgets();
  806.  
  807. D(    printf ("leaving XFE_Menu::setMenuSpec()\n");)
  808. }
  809.  
  810. void
  811. XFE_Menu::cascade_update_cb(Widget w,
  812.                    XtPointer clientData,
  813.                    XtPointer /*callData*/)
  814. {
  815.   Widget submenu = NULL;
  816.   XFE_Menu *mb = (XFE_Menu*)clientData;
  817.  
  818.   XP_ASSERT(mb);
  819.  
  820.   XtVaGetValues(w,
  821.         XmNsubMenuId, &submenu,
  822.         NULL);
  823.  
  824.   mb->updateSubMenu(submenu);
  825. }
  826.  
  827. static CommandType
  828. get_cmd_type(Widget w)
  829. {
  830.     XtPointer   userData;
  831.     MenuSpec*   spec;
  832.     CommandType cmd;
  833.  
  834.     XtVaGetValues(w,
  835.                   XmNuserData, &userData,
  836.                   NULL);
  837.  
  838.     spec = (MenuSpec*)userData;
  839.     cmd = spec->getCmdName();
  840.  
  841.     return cmd;
  842. }
  843.  
  844. void
  845. XFE_Menu::pushb_arm_cb(Widget w, XtPointer clientData, XtPointer)
  846. {
  847.   XFE_Menu*   obj = (XFE_Menu*)clientData;
  848.   CommandType cmd = get_cmd_type(w);
  849.  
  850.   obj->m_parentFrame->notifyInterested(Command::commandArmedCallback,
  851.                                        (void*)cmd);
  852. }
  853.  
  854. void
  855. XFE_Menu::pushb_activate_cb(Widget w, XtPointer clientData, XtPointer callData)
  856. {
  857.   XFE_Menu*                   obj = (XFE_Menu*)clientData;
  858.   XmPushButtonCallbackStruct* cd = (XmPushButtonCallbackStruct *)callData;
  859.  
  860.   XtPointer userData;
  861.   XtVaGetValues(w,
  862.         XmNuserData, &userData,
  863.         NULL);
  864.  
  865.   MenuSpec*   spec = (MenuSpec*)userData;
  866.   CommandType cmd = spec->getCmdName();
  867.   
  868.   XFE_CommandInfo e_info(XFE_COMMAND_BUTTON_ACTIVATE,
  869.                          w,
  870.                          cd->event,
  871.                          spec->cmd_args, 0);
  872.   
  873.   xfe_ExecuteCommand(obj->m_parentFrame, cmd, spec->callData, &e_info);
  874.  
  875.   obj->m_parentFrame->notifyInterested(Command::commandDispatchedCallback,
  876.                                        (void*)cmd);
  877. }
  878.  
  879. void
  880. XFE_Menu::pushb_disarm_cb(Widget w, XtPointer clientData, XtPointer)
  881. {
  882.   XFE_Menu*   obj = (XFE_Menu*)clientData;
  883.   CommandType cmd = get_cmd_type(w);
  884.  
  885.   obj->m_parentFrame->notifyInterested(Command::commandDisarmedCallback,
  886.                                        (void*)cmd);
  887. }
  888.  
  889. void
  890. XFE_Menu::toggleb_arm_cb(Widget w, XtPointer clientData, XtPointer)
  891. {
  892.   XFE_Menu*   obj = (XFE_Menu*)clientData;
  893.   CommandType cmd = get_cmd_type(w);
  894.  
  895.   obj->m_parentFrame->notifyInterested(Command::commandArmedCallback,
  896.                                        (void*)cmd);
  897. }
  898.  
  899. void
  900. XFE_Menu::toggleb_activate_cb(Widget w,
  901.                               XtPointer clientData, XtPointer callData)
  902. {
  903.   XmToggleButtonCallbackStruct* cbs = (XmToggleButtonCallbackStruct*)callData;
  904.   XFE_Menu* obj = (XFE_Menu*)clientData;
  905.  
  906.   XtPointer userData;
  907.   XtVaGetValues(w,
  908.         XmNuserData, &userData,
  909.         NULL);
  910.  
  911.   MenuSpec*   spec = (MenuSpec*)userData;
  912.   CommandType cmd = spec->getCmdName();
  913.   
  914.   XFE_CommandInfo e_info(XFE_COMMAND_BUTTON_ACTIVATE,
  915.                          w,
  916.                          cbs->event,
  917.                          spec->cmd_args, 0);
  918.   
  919.   xfe_ExecuteCommand(obj->m_parentFrame, cmd, spec->callData, &e_info);
  920.  
  921.   obj->m_parentFrame->notifyInterested(Command::commandDispatchedCallback,
  922.                                        (void*)cmd);
  923. }
  924.  
  925. void
  926. XFE_Menu::toggleb_disarm_cb(Widget w, XtPointer clientData, XtPointer)
  927. {
  928.   XFE_Menu*   obj = (XFE_Menu*)clientData;
  929.   CommandType cmd = get_cmd_type(w);
  930.  
  931.   obj->notifyInterested(Command::commandDisarmedCallback, (void*)cmd);
  932. }
  933.  
  934. void
  935. XFE_Menu::radiob_arm_cb(Widget w, XtPointer clientData, XtPointer)
  936. {
  937.   XFE_Menu*   obj = (XFE_Menu*)clientData;
  938.   CommandType cmd = get_cmd_type(w);
  939.  
  940.   obj->m_parentFrame->notifyInterested(Command::commandArmedCallback,
  941.                                        (void*)cmd);
  942. }
  943.  
  944. void
  945. XFE_Menu::radiob_activate_cb(Widget w,
  946.                               XtPointer clientData, XtPointer callData)
  947. {
  948.   XmToggleButtonCallbackStruct* cbs = (XmToggleButtonCallbackStruct*)callData;
  949.   XFE_Menu* obj = (XFE_Menu*)clientData;
  950.  
  951.   XtPointer userData;
  952.   XtVaGetValues(w,
  953.         XmNuserData, &userData,
  954.         NULL);
  955.  
  956.   MenuSpec*   spec = (MenuSpec*)userData;
  957.  
  958.   //
  959.   //    Only do stuff, if we are being turned on. This is not right,
  960.   //    but we have code which depends on it.
  961.   //
  962.   if (!cbs->set)
  963.     return;
  964.  
  965.   CommandType cmd = spec->getCmdName();
  966.   
  967.   XFE_CommandInfo e_info(XFE_COMMAND_BUTTON_ACTIVATE,
  968.                          w,
  969.                          cbs->event,
  970.                          spec->cmd_args, 0);
  971.   
  972.   xfe_ExecuteCommand(obj->m_parentFrame, cmd, spec->callData, &e_info);
  973.  
  974.   obj->m_parentFrame->notifyInterested(Command::commandDispatchedCallback,
  975.                                        (void*)cmd);
  976. }
  977.  
  978. void
  979. XFE_Menu::radiob_disarm_cb(Widget w, XtPointer clientData, XtPointer)
  980. {
  981.   XFE_Menu*   obj = (XFE_Menu*)clientData;
  982.   CommandType cmd = get_cmd_type(w);
  983.  
  984.   obj->notifyInterested(Command::commandDisarmedCallback, (void*)cmd);
  985. }
  986.  
  987. #ifdef DELAYED_MENU_CREATION
  988. void
  989. XFE_Menu::delayedCreatePulldown(Widget cascade, Widget pulldown, MenuSpec *spec)
  990. {
  991.     if (spec)
  992.         {
  993.             MenuSpec *cur_spec;
  994.             Widget items[150];
  995.             int num_items = 0;
  996.             
  997.             cur_spec = spec;
  998.             while (cur_spec->menuItemName)
  999.                 {
  1000.                     items[num_items] = createMenuItem(cur_spec, cascade, pulldown);
  1001.                     
  1002.                     if ((items[num_items] != NULL) && // we return NULL for DYNA_MENUITEMS
  1003.                         (! cur_spec->do_not_manage))  // we set this field for non-Communicator menu items
  1004.                         num_items++;
  1005.                     
  1006.                     cur_spec ++;
  1007.                 }
  1008.             
  1009.             if (num_items)
  1010.                 XtManageChildren(items, num_items);
  1011.         }
  1012. }
  1013.  
  1014. void
  1015. XFE_Menu::delayed_create_pulldown(Widget w, XtPointer cd, XtPointer)
  1016. {
  1017.     Widget submenu;
  1018.     MenuSpec *spec;
  1019.     XFE_Menu *mb = (XFE_Menu*)cd;
  1020.  
  1021.     XP_ASSERT(mb);
  1022.     
  1023.     XtVaGetValues(w,
  1024.                   XmNsubMenuId, &submenu,
  1025.                   XmNuserData, &spec,
  1026.                   NULL);
  1027.  
  1028. D(    printf ("Creating pulldown menu\n");)
  1029.  
  1030.     mb->delayedCreatePulldown(w, submenu, spec->submenu);
  1031.  
  1032.     XtRemoveCallback(w, XmNcascadingCallback, delayed_create_pulldown, mb);
  1033.  
  1034.     XtAddCallback(w, XmNcascadingCallback, cascade_update_cb, mb);
  1035.  
  1036.     /* this is needed because the above delayedCreatePulldown possibly attached
  1037.        dynamic menus to the pulldown, and we need to trigger them to create their
  1038.        menu items.  It also sensitizes the menu because of the above line.
  1039.        */
  1040.     XtCallCallbacks(w, XmNcascadingCallback, NULL);
  1041. }
  1042.  
  1043. #endif
  1044.