home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / XfeWidgets / Xfe / Cascade.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  35.8 KB  |  1,269 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. /*                                                                        */
  20. /* Name:        <Xfe/Cascade.c>                                            */
  21. /* Description:    XfeCascade widget source.                                */
  22. /* Author:        Ramiro Estrugo <ramiro@netscape.com>                    */
  23. /*                                                                        */
  24. /*----------------------------------------------------------------------*/
  25.  
  26.  
  27. #include <Xfe/CascadeP.h>
  28. #include <Xfe/ManagerP.h>
  29.  
  30. #include <Xm/RowColumnP.h>
  31.  
  32. /*----------------------------------------------------------------------*/
  33. /*                                                                        */
  34. /* Warnings and messages                                                */
  35. /*                                                                        */
  36. /*----------------------------------------------------------------------*/
  37. #define MESSAGE1 "Widget is not a XfeButton."
  38. #define MESSAGE2 "XmNsubMenuId is a read-only resource."
  39. #define MESSAGE3 "XmNpoppedUp is a read-only resource."
  40. #define MESSAGE4 "XmNtorn is a read-only resource."
  41.  
  42. #define SUB_MENU_ID_NAME        "PopupMenu"
  43.  
  44. /*
  45.  * In order to get popup menus working as if they were pulldown menus,
  46.  * we need to trick motif into ignoring the event up until the point when
  47.  * we know it is ok to pop it up.  This will happen either right away,
  48.  * or after the mapping delay timeout expires (based on the value of 
  49.  * XmNmappingDelay). We accomplish this by swapping these two values for
  50.  * the popup's XmNmenuPost resource.  This scheme seems pretty robust.  If 
  51.  * a user happens to have a 7 button mouse and they hit Button7 on the 
  52.  * widget, then a (harmless ?) passive grab will occur.  We make sure the
  53.  * grab does not screw the user by installing a ButtonPress event handler
  54.  * on the widget and ungrabing the pointer just in case.
  55.  */
  56. #define POPUP_IGNORE            "<Btn3Down>"
  57. #define POPUP_ACCEPT            "<Btn1Down>"
  58.  
  59. /* Tear off model for cascade */
  60. #define TEAR_MODEL(cp) \
  61. ((cp)->allow_tear_off ? XmTEAR_OFF_ENABLED : XmTEAR_OFF_DISABLED)
  62.  
  63. /* Popup shell */
  64. #define POPUP_SHELL(cp) \
  65. (XtParent((cp)->sub_menu_id))
  66.  
  67. /*----------------------------------------------------------------------*/
  68. /*                                                                        */
  69. /* Core class methods                                                    */
  70. /*                                                                        */
  71. /*----------------------------------------------------------------------*/
  72. static void     Initialize        (Widget,Widget,ArgList,Cardinal *);
  73. static void     Destroy            (Widget);
  74. static Boolean    SetValues        (Widget,Widget,Widget,ArgList,Cardinal *);
  75.  
  76. /*----------------------------------------------------------------------*/
  77. /*                                                                        */
  78. /* XfePrimitive class methods                                            */
  79. /*                                                                        */
  80. /*----------------------------------------------------------------------*/
  81. static void    PreferredGeometry    (Widget,Dimension *,Dimension *);
  82. static void    DrawComponents        (Widget,XEvent *,Region,XRectangle *);
  83. static void    LayoutComponents    (Widget);
  84.  
  85. /*----------------------------------------------------------------------*/
  86. /*                                                                        */
  87. /* XfeCascade action procedures                                            */
  88. /*                                                                        */
  89. /*----------------------------------------------------------------------*/
  90. static void     Arm                (Widget,XEvent *,char **,Cardinal *);
  91. static void     Activate        (Widget,XEvent *,char **,Cardinal *);
  92. static void     Disarm            (Widget,XEvent *,char **,Cardinal *);
  93. static void     Post            (Widget,XEvent *,char **,Cardinal *);
  94. static void     Unpost            (Widget,XEvent *,char **,Cardinal *);
  95.  
  96. /*----------------------------------------------------------------------*/
  97. /*                                                                        */
  98. /* Misc XfeCascade functions                                            */
  99. /*                                                                        */
  100. /*----------------------------------------------------------------------*/
  101. static void        DelayTimeout        (XtPointer,XtIntervalId *);
  102. static void        DrawCascadeArrow    (Widget,XEvent *,Region,XRectangle *);
  103. static void        LayoutCascadeArrow    (Widget);
  104. static void        GetPostPosition        (Widget,Position *,Position *);
  105. static void        InvokeTearCallback    (Widget,XEvent *,Boolean);
  106.  
  107. /*----------------------------------------------------------------------*/
  108. /*                                                                        */
  109. /* SubMenu event handlers and callbacks                                    */
  110. /*                                                                        */
  111. /*----------------------------------------------------------------------*/
  112. static void    SubMenuEH                (Widget,XtPointer,XEvent *,Boolean *);
  113. static void    SubMenuTearCB            (Widget,XtPointer,XtPointer);
  114. static void    UnGrabEH                (Widget,XtPointer,XEvent *,Boolean *);
  115.  
  116. /*----------------------------------------------------------------------*/
  117. /*                                                                        */
  118. /* XfeCascade Resources                                                    */
  119. /*                                                                        */
  120. /*----------------------------------------------------------------------*/
  121. static XtResource resources[] = 
  122. {
  123.     /* Callback resources */         
  124.     { 
  125.         XmNcascadingCallback,
  126.         XmCCallback,
  127.         XmRCallback,
  128.         sizeof(XtCallbackList),
  129.         XtOffsetOf(XfeCascadeRec,xfe_cascade . cascading_callback),
  130.         XmRImmediate, 
  131.         (XtPointer) NULL
  132.     },
  133.  
  134.     { 
  135.         XmNpopdownCallback,
  136.         XmCCallback,
  137.         XmRCallback,
  138.         sizeof(XtCallbackList),
  139.         XtOffsetOf(XfeCascadeRec,xfe_cascade . popdown_callback),
  140.         XmRImmediate, 
  141.         (XtPointer) NULL
  142.     },
  143.     { 
  144.         XmNpopupCallback,
  145.         XmCCallback,
  146.         XmRCallback,
  147.         sizeof(XtCallbackList),
  148.         XtOffsetOf(XfeCascadeRec,xfe_cascade . popup_callback),
  149.         XmRImmediate, 
  150.         (XtPointer) NULL
  151.     },
  152.     { 
  153.         XmNsubmenuTearCallback,
  154.         XmCCallback,
  155.         XmRCallback,
  156.         sizeof(XtCallbackList),
  157.         XtOffsetOf(XfeCascadeRec,xfe_cascade . submenu_tear_callback),
  158.         XmRImmediate, 
  159.         (XtPointer) NULL
  160.     },
  161.  
  162.     /* Sub menu resources */
  163.     { 
  164.         XmNmappingDelay,
  165.         XmCMappingDelay,
  166.         XmRInt,
  167.         sizeof(int),
  168.         XtOffsetOf(XfeCascadeRec , xfe_cascade . mapping_delay),
  169.         XmRImmediate, 
  170.          (XtPointer) XfeDEFAULT_MAPPING_DELAY
  171.     },
  172.     { 
  173.         XmNsubMenuId,
  174.         XmCReadOnly,
  175.         XmRWidget,
  176.         sizeof(Widget),
  177.         XtOffsetOf(XfeCascadeRec , xfe_cascade . sub_menu_id),
  178.         XmRImmediate, 
  179.         (XtPointer) NULL
  180.     },
  181.     { 
  182.         XmNsubMenuAlignment,
  183.         XmCSubMenuAlignment,
  184.         XmRAlignment,
  185.         sizeof(unsigned char),
  186.         XtOffsetOf(XfeCascadeRec , xfe_cascade . sub_menu_alignment),
  187.         XmRImmediate, 
  188.         (XtPointer) XmALIGNMENT_BEGINNING
  189.     },
  190.     { 
  191.         XmNsubMenuLocation,
  192.         XmCSubMenuLocation,
  193.         XmRLocationType,
  194.         sizeof(unsigned char),
  195.         XtOffsetOf(XfeCascadeRec , xfe_cascade . sub_menu_location),
  196.         XmRImmediate, 
  197.         (XtPointer) XmLOCATION_SOUTH
  198.     },
  199.     { 
  200.         XmNpoppedUp,
  201.         XmCReadOnly,
  202.         XmRBoolean,
  203.         sizeof(Boolean),
  204.         XtOffsetOf(XfeCascadeRec , xfe_cascade . popped_up),
  205.         XmRImmediate, 
  206.         (XtPointer) False
  207.     },
  208.     { 
  209.         XmNmatchSubMenuWidth,
  210.         XmCMatchSubMenuWidth,
  211.         XmRBoolean,
  212.         sizeof(Boolean),
  213.         XtOffsetOf(XfeCascadeRec , xfe_cascade . match_sub_menu_width),
  214.         XmRImmediate, 
  215.         (XtPointer) False
  216.     },
  217.  
  218.     
  219.     /* Tear resources */
  220.     { 
  221.         XmNtorn,
  222.         XmCReadOnly,
  223.         XmRBoolean,
  224.         sizeof(Boolean),
  225.         XtOffsetOf(XfeCascadeRec , xfe_cascade . torn),
  226.         XmRImmediate, 
  227.         (XtPointer) False
  228.     },
  229.     { 
  230.         XmNallowTearOff,
  231.         XmCBoolean,
  232.         XmRBoolean,
  233.         sizeof(Boolean),
  234.         XtOffsetOf(XfeCascadeRec , xfe_cascade . allow_tear_off),
  235.         XmRImmediate, 
  236.         (XtPointer) False
  237.     },
  238.     { 
  239.         XmNtornShellTitle,
  240.         XmCTornShellTitle,
  241.         XmRString,
  242.         sizeof(String),
  243.         XtOffsetOf(XfeCascadeRec , xfe_cascade . torn_shell_title),
  244.         XmRImmediate, 
  245.         (XtPointer) NULL
  246.     },
  247.  
  248.     /* Cascade arrow resources */
  249.     { 
  250.         XmNcascadeArrowDirection,
  251.         XmCCascadeArrowDirection,
  252.         XmRArrowDirection,
  253.         sizeof(unsigned char),
  254.         XtOffsetOf(XfeCascadeRec , xfe_cascade . cascade_arrow_direction),
  255.         XmRImmediate, 
  256.         (XtPointer) XmARROW_DOWN
  257.     },
  258.     { 
  259.         XmNcascadeArrowLocation,
  260.         XmCCascadeArrowLocation,
  261.         XmRLocationType,
  262.         sizeof(unsigned char),
  263.         XtOffsetOf(XfeCascadeRec , xfe_cascade . cascade_arrow_location),
  264.         XmRImmediate, 
  265.         (XtPointer) XmLOCATION_SOUTH_WEST
  266.     },
  267.     { 
  268.         XmNcascadeArrowHeight,
  269.         XmCCascadeArrowHeight,
  270.         XmRVerticalDimension,
  271.         sizeof(Dimension),
  272.         XtOffsetOf(XfeCascadeRec , xfe_cascade . cascade_arrow_rect . height),
  273.         XmRImmediate, 
  274.         (XtPointer) 3
  275.     },
  276.     { 
  277.         XmNcascadeArrowWidth,
  278.         XmCCascadeArrowWidth,
  279.         XmRHorizontalDimension,
  280.         sizeof(Dimension),
  281.         XtOffsetOf(XfeCascadeRec , xfe_cascade . cascade_arrow_rect . width),
  282.         XmRImmediate, 
  283.         (XtPointer) 5
  284.     },
  285.     { 
  286.         XmNdrawCascadeArrow,
  287.         XmCDrawCascadeArrow,
  288.         XmRBoolean,
  289.         sizeof(Boolean),
  290.         XtOffsetOf(XfeCascadeRec , xfe_cascade . draw_cascade_arrow),
  291.         XmRImmediate, 
  292.         (XtPointer) False
  293.     },
  294.  
  295.     /* Sub menu resources */
  296. };
  297.  
  298. /*----------------------------------------------------------------------*/
  299. /*                                                                        */
  300. /* XfeButton Synthetic Resources                                        */
  301. /*                                                                        */
  302. /*----------------------------------------------------------------------*/
  303. static XmSyntheticResource syn_resources[] =
  304. {
  305.     {
  306.         XmNcascadeArrowHeight,
  307.         sizeof(Dimension),
  308.         XtOffsetOf(XfeCascadeRec , xfe_cascade . cascade_arrow_rect . height),
  309.         _XmFromVerticalPixels,
  310.         _XmToVerticalPixels 
  311.     },
  312.     {
  313.         XmNcascadeArrowWidth,
  314.         sizeof(Dimension),
  315.         XtOffsetOf(XfeCascadeRec , xfe_cascade . cascade_arrow_rect . width),
  316.         _XmFromHorizontalPixels,
  317.         _XmToHorizontalPixels 
  318.     },
  319. };
  320.  
  321. /*----------------------------------------------------------------------*/
  322. /*                                                                        */
  323. /* XfeButton actions                                                    */
  324. /*                                                                        */
  325. /*----------------------------------------------------------------------*/
  326. static XtActionsRec actions[] = 
  327. {
  328.     { "Arm",                Arm                },
  329.     { "Activate",            Activate        },
  330.     { "Disarm",                Disarm            },
  331. };
  332.  
  333. /*----------------------------------------------------------------------*/
  334. /*                                                                        */
  335. /* XfeCascade widget class record initialization                        */
  336. /*                                                                        */
  337. /*----------------------------------------------------------------------*/
  338. _XFE_WIDGET_CLASS_RECORD(cascade,Cascade) =
  339. {
  340.     {
  341.         /* Core Part */
  342.         (WidgetClass) &xfeButtonClassRec,        /* superclass             */
  343.         "XfeCascade",                            /* class_name             */
  344.         sizeof(XfeCascadeRec),                    /* widget_size            */
  345.         NULL,                                    /* class_initialize       */
  346.         NULL,                                    /* class_part_initialize*/
  347.         FALSE,                                  /* class_inited           */
  348.         Initialize,                             /* initialize             */
  349.         NULL,                                   /* initialize_hook        */
  350.         XtInheritRealize,                       /* realize                */
  351.         actions,                                /* actions                */
  352.         XtNumber(actions),                        /* num_actions            */
  353.         resources,                              /* resources              */
  354.         XtNumber(resources),                    /* num_resources          */
  355.         NULLQUARK,                              /* xrm_class              */
  356.         TRUE,                                   /* compress_motion        */
  357.         XtExposeCompressMaximal,                /* compress_exposure      */
  358.         TRUE,                                   /* compress_enterleave    */
  359.         FALSE,                                  /* visible_interest       */
  360.         Destroy,                                /* destroy                */
  361.         XtInheritResize,                        /* resize                 */
  362.         XtInheritExpose,                        /* expose                 */
  363.         SetValues,                              /* set_values             */
  364.         NULL,                                   /* set_values_hook        */
  365.         XtInheritSetValuesAlmost,                /* set_values_almost      */
  366.         NULL,                                    /* get_values_hook        */
  367.         NULL,                                   /* accept_focus           */
  368.         XtVersion,                              /* version                */
  369.         NULL,                                   /* callback_private       */
  370.         XtInheritTranslations,                    /* tm_table               */
  371.         XtInheritQueryGeometry,                    /* query_geometry         */
  372.         XtInheritDisplayAccelerator,            /* display accel          */
  373.         NULL,                                   /* extension              */
  374.     },
  375.  
  376.     /* XmPrimitive Part */
  377.     {
  378.         XmInheritBorderHighlight,                /* border_highlight        */
  379.         XmInheritBorderUnhighlight,                /* border_unhighlight     */
  380.         XtInheritTranslations,                  /* translations           */
  381.         XmInheritArmAndActivate,                /* arm_and_activate       */
  382.         syn_resources,                            /* syn resources          */
  383.         XtNumber(syn_resources),                /* num syn_resources      */
  384.         NULL,                                    /* extension              */
  385.     },
  386.     
  387.     /* XfePrimitive Part */
  388.     {
  389.         XfeInheritBitGravity,                    /* bit_gravity            */
  390.         PreferredGeometry,                        /* preferred_geometry    */
  391.         XfeInheritMinimumGeometry,                /* minimum_geometry        */
  392.         XfeInheritUpdateRect,                    /* update_rect            */
  393.         NULL,                                    /* prepare_components    */
  394.         LayoutComponents,                        /* layout_components    */
  395.         XfeInheritDrawBackground,                /* draw_background        */
  396.         XfeInheritDrawShadow,                    /* draw_shadow            */
  397.         DrawComponents,                            /* draw_components        */
  398.         NULL,                                    /* extension            */
  399.     },
  400.  
  401.     /* XfeLabel Part */
  402.     {
  403.         XfeInheritLayoutString,                    /* layout_string        */
  404.         XfeInheritDrawString,                    /* draw_string            */
  405.         XfeInheritDrawSelection,                /* draw_selection        */
  406.         XfeInheritGetLabelGC,                    /* get_label_gc            */
  407.         XfeInheritGetSelectionGC,                /* get_selection_gc        */
  408.         NULL,                                    /* extension            */
  409.     },
  410.  
  411.     /* XfeButton Part */
  412.     {
  413.         XfeInheritLayoutPixmap,                    /* layout_pixmap        */
  414.         XfeInheritDrawPixmap,                    /* draw_pixmap            */
  415.         XfeInheritDrawRaiseBorder,                /* draw_raise_border    */
  416.         XfeInheritArmTimeout,                    /* arm_timeout            */
  417.         NULL,                                    /* extension            */
  418.     },
  419.  
  420.     /* XfeCascade Part */
  421.     {
  422.         NULL,                                    /* extension            */
  423.     },
  424. };
  425.  
  426. /*----------------------------------------------------------------------*/
  427. /*                                                                        */
  428. /* xfeCascadeWidgetClass declaration.                                    */
  429. /*                                                                        */
  430. /*----------------------------------------------------------------------*/
  431. _XFE_WIDGET_CLASS(cascade,Cascade);
  432.  
  433. /*----------------------------------------------------------------------*/
  434. /*                                                                        */
  435. /* Core class methods                                                    */
  436. /*                                                                        */
  437. /*----------------------------------------------------------------------*/
  438. static void
  439. Initialize(Widget rw,Widget nw,ArgList args,Cardinal *nargs)
  440. {
  441.     XfeCascadePart *    cp = _XfeCascadePart(nw);
  442.     Arg                    xargs[3];
  443.     Cardinal            n;
  444.  
  445.     /* Make sure rep types are ok */
  446.     XfeRepTypeCheck(nw,XmRLocationType,&cp->cascade_arrow_location,
  447.                     XmLOCATION_SOUTH_WEST);
  448.  
  449.     XfeRepTypeCheck(nw,XmRArrowDirection,&cp->cascade_arrow_direction,
  450.                     XmARROW_DOWN);
  451.  
  452.     XfeRepTypeCheck(nw,XmRAlignment,&cp->sub_menu_alignment,
  453.                     XmALIGNMENT_BEGINNING);
  454.  
  455.     XfeRepTypeCheck(nw,XmRLocationType,&cp->sub_menu_location,
  456.                     XmLOCATION_SOUTH);
  457.  
  458.     /* Create popup using our probably non-standard visual/colormap/depth */
  459.     n = 0;
  460.  
  461.     XtSetArg(xargs[n],XmNcolormap,    XfeColormap(nw));    n++;
  462.     XtSetArg(xargs[n],XmNdepth,        XfeDepth(nw));        n++;
  463.     XtSetArg(xargs[n],XmNvisual,    XfeVisual(nw));        n++;
  464.  
  465.     cp->sub_menu_id = XmCreatePopupMenu(nw,SUB_MENU_ID_NAME,xargs,n);
  466.  
  467.     XtVaSetValues(cp->sub_menu_id,XmNmenuPost,POPUP_IGNORE,NULL);
  468.  
  469.     /* Add ungrab event handler to cascade button */
  470.     XtInsertEventHandler(nw,
  471.                          ButtonPressMask,
  472.                          True,
  473.                          UnGrabEH,
  474.                          (XtPointer) nw,
  475.                          XtListTail);
  476.  
  477.     /* Add map/unmap event handler to sub menu's parent shell */
  478.     XtAddEventHandler(POPUP_SHELL(cp),
  479.                       StructureNotifyMask,
  480.                       True,
  481.                       SubMenuEH,
  482.                       (XtPointer) nw);
  483.  
  484.     /* Add tear callbacks top submenu */
  485.     XtAddCallback(cp->sub_menu_id,
  486.                   XmNtearOffMenuActivateCallback,
  487.                   SubMenuTearCB,
  488.                   (XtPointer) nw);
  489.  
  490.     XtAddCallback(cp->sub_menu_id,
  491.                   XmNtearOffMenuDeactivateCallback,
  492.                   SubMenuTearCB,
  493.                   (XtPointer) nw);
  494.  
  495.     /* Initialize private members */
  496.     cp->delay_timer_id        = 0;
  497.     cp->default_menu_cursor    = XmGetMenuCursor(XtDisplay(nw));
  498.  
  499.     /* Update the tear model */
  500.     XtVaSetValues(cp->sub_menu_id,XmNtearOffModel,TEAR_MODEL(cp),NULL);
  501.  
  502.     /* Update the torn shell title */
  503.     if (cp->torn_shell_title)
  504.     {
  505.         cp->torn_shell_title = (String) XtNewString(cp->torn_shell_title);
  506.     }
  507.     else
  508.     {
  509.         cp->torn_shell_title = (String) XtNewString(XtName(nw));
  510.     }
  511.  
  512.     XtVaSetValues(POPUP_SHELL(cp),XmNtitle,cp->torn_shell_title,NULL);
  513.  
  514.     /* Finish of initialization */
  515.     _XfePrimitiveChainInitialize(rw,nw,xfeCascadeWidgetClass);
  516. }
  517. /*----------------------------------------------------------------------*/
  518. static void
  519. Destroy(Widget w)
  520. {
  521.     XfeCascadePart *    cp = _XfeCascadePart(w);
  522.  
  523.     /* Free the torn shell title if needed */
  524.     if (cp->torn_shell_title)
  525.     {
  526.         XtFree(cp->torn_shell_title);
  527.     }
  528.  
  529.     /* Remove all CallBacks */
  530.     /* XtRemoveAllCallbacks(w,XmNpopdownCallback); */
  531.     /* XtRemoveAllCallbacks(w,XmNpopupCallback); */
  532.     /* XtRemoveAllCallbacks(w,XmNcascadingCallback); */
  533. }
  534. /*----------------------------------------------------------------------*/
  535. static Boolean
  536. SetValues(Widget ow,Widget rw,Widget nw,ArgList args,Cardinal *nargs)
  537. {
  538.     XfeCascadePart *    np = _XfeCascadePart(nw);
  539.     XfeCascadePart *    op = _XfeCascadePart(ow);
  540.  
  541.     /* sub_menu_id */
  542.     if (np->sub_menu_id != op->sub_menu_id)
  543.     {
  544.         np->sub_menu_id = op->sub_menu_id;
  545.  
  546.         _XfeWarning(nw,MESSAGE2);
  547.     }
  548.  
  549.     /* popped_up */
  550.     if (np->popped_up != op->popped_up)
  551.     {
  552.         np->popped_up = op->popped_up;
  553.  
  554.         _XfeWarning(nw,MESSAGE3);
  555.     }
  556.  
  557.     /* torn */
  558.     if (np->torn != op->torn)
  559.     {
  560.         np->torn = op->torn;
  561.  
  562.         _XfeWarning(nw,MESSAGE4);
  563.     }
  564.  
  565.     /* allow_tear_off */
  566.     if (np->allow_tear_off != op->allow_tear_off)
  567.     {
  568.         XtVaSetValues(np->sub_menu_id,XmNtearOffModel,TEAR_MODEL(np),NULL);
  569.     }
  570.  
  571.     /* torn_shell_title */
  572.     if (np->torn_shell_title != op->torn_shell_title)
  573.     {
  574.         if (op->torn_shell_title)
  575.         {
  576.             XtFree(op->torn_shell_title);
  577.         }
  578.  
  579.         if (np->torn_shell_title)
  580.         {
  581.             np->torn_shell_title = (String) XtNewString(np->torn_shell_title);
  582.         }
  583.         else
  584.         {
  585.             np->torn_shell_title = (String) XtNewString(" ");
  586.         }
  587.  
  588.         XtVaSetValues(POPUP_SHELL(np),XmNtitle,np->torn_shell_title,NULL);
  589.     }
  590.  
  591.     /* sub_menu_alignment */
  592.     if (np->sub_menu_alignment != op->sub_menu_alignment)
  593.     {
  594.         /* Make sure the new sub menu alignment is ok */
  595.         XfeRepTypeCheck(nw,XmRAlignment,&np->sub_menu_alignment,
  596.                         XmALIGNMENT_BEGINNING);
  597.  
  598.         _XfeConfigFlags(nw) |= XfeConfigExpose;   
  599.     }
  600.  
  601.     /* sub_menu_location */
  602.     if (np->sub_menu_location != op->sub_menu_location)
  603.     {
  604.         /* Make sure the new sub menu location is ok */
  605.         XfeRepTypeCheck(nw,XmRLocationType,&np->sub_menu_location,
  606.                         XmLOCATION_SOUTH);
  607.     }
  608.  
  609.     /* cascade_arrow_location */
  610.     if (np->cascade_arrow_location != op->cascade_arrow_location)
  611.     {
  612.         /* Make sure the new cascade arrow location is ok */
  613.         XfeRepTypeCheck(nw,XmRLocationType,&np->cascade_arrow_location,
  614.                         XmLOCATION_SOUTH_WEST);
  615.     }
  616.  
  617.  
  618.     return _XfePrimitiveChainSetValues(ow,rw,nw,xfeCascadeWidgetClass);
  619. }
  620. /*----------------------------------------------------------------------*/
  621.  
  622. /*----------------------------------------------------------------------*/
  623. /*                                                                        */
  624. /* XfePrimitive methods                                                    */
  625. /*                                                                        */
  626. /*----------------------------------------------------------------------*/
  627. static void
  628. PreferredGeometry(Widget w,Dimension *width,Dimension *height)
  629. {
  630.     XfeCascadePart *        cp = _XfeCascadePart(w);
  631.     XfeButtonWidgetClass    bwc = (XfeButtonWidgetClass) xfeButtonWidgetClass;
  632.  
  633.     /* */
  634.     (*bwc->xfe_primitive_class.preferred_geometry)(w,width,height);
  635.  
  636.     /* If the sub menu has children, use its width if needed */
  637.     if (_XfeIsAlive(cp->sub_menu_id) && 
  638.         _XfemNumChildren(cp->sub_menu_id) &&
  639.         cp->match_sub_menu_width)
  640.     {
  641.         *width = _XfeWidth(cp->sub_menu_id);
  642.     }
  643. }
  644. /*----------------------------------------------------------------------*/
  645. static void
  646. LayoutComponents(Widget w)
  647. /*----------------------------------------------------------------------*/
  648. {
  649.     /* Invoke layout_string method */
  650.     _XfeLabelLayoutString(w);
  651.  
  652.     /* Invoke layout_pixmap method */
  653.     _XfeButtonLayoutPixmap(w);
  654.  
  655.     /* Layout the cascade arrow */
  656.     LayoutCascadeArrow(w);
  657. }
  658. /*----------------------------------------------------------------------*/
  659. static void
  660. DrawComponents(Widget w,XEvent *event,Region region,XRectangle * clip_rect)
  661. {
  662.     /* Invoke draw_string method */
  663.     _XfeLabelDrawString(w,event,region,clip_rect);
  664.  
  665.     /* Invoke draw_pixmap method */
  666.     _XfeButtonDrawPixmap(w,event,region,clip_rect);
  667.  
  668.     /* Invoke draw_border method */
  669.     _XfeButtonDrawRaiseBorder(w,event,region,clip_rect);
  670.  
  671.     /* Draw Cascade Arrow */
  672.     DrawCascadeArrow(w,event,region,clip_rect);
  673. }
  674. /*----------------------------------------------------------------------*/
  675.  
  676.  
  677. /*----------------------------------------------------------------------*/
  678. /*                                                                        */
  679. /* Misc XfeCascade functions                                            */
  680. /*                                                                        */
  681. /*----------------------------------------------------------------------*/
  682. static void
  683. DelayTimeout(XtPointer client_data,XtIntervalId * id)
  684. {
  685.     Widget                    w = (Widget) client_data;
  686.     XfeCascadePart *        cp = _XfeCascadePart(w);
  687.     XfeButtonPart *            bp = _XfeButtonPart(w);
  688.  
  689.     /* If we are still armed and the pointer remains in the button */
  690.     if (bp->armed && _XfePointerInside(w))
  691.     {
  692.         Post(w,NULL,NULL,NULL);
  693.     }
  694.  
  695.     /* Reset the timer */
  696.     cp->delay_timer_id = 0;
  697. }
  698. /*----------------------------------------------------------------------*/
  699. static void
  700. DrawCascadeArrow(Widget w,XEvent *event,Region region,XRectangle * clip_rect)
  701. {
  702.     XfeCascadePart *        cp = _XfeCascadePart(w);
  703.     XfeButtonPart *            bp = _XfeButtonPart(w);
  704.     Dimension                offset;
  705.  
  706.     /* Make sure the cascade arrow is actually needed before drawing it */
  707.     if (!cp->draw_cascade_arrow || 
  708.         !cp->cascade_arrow_rect.height || 
  709.         !cp->cascade_arrow_rect.width)
  710.     {
  711.         return;
  712.     }
  713.  
  714.     /* Compute the arming offset */
  715.     offset = bp->armed ? bp->arm_offset : 0;
  716.  
  717.     /* Draw the arrow as an XmArrowButton would */
  718.     if (bp->emulate_motif)
  719.     {
  720.         XfeDrawMotifArrow(XtDisplay(w),
  721.                           _XfePrimitiveDrawable(w), 
  722.                           _XfeTopShadowGC(w),
  723.                           _XfeTopShadowGC(w),
  724.                           _XfeBackgroundGC(w),
  725.                           cp->cascade_arrow_rect.x + offset,
  726.                           cp->cascade_arrow_rect.y + offset, 
  727.                           cp->cascade_arrow_rect.width,
  728.                           cp->cascade_arrow_rect.height,
  729.                           cp->cascade_arrow_direction,
  730.                           2, /* hard coded to be compatible with Motif */
  731.                           bp->armed);
  732.     }
  733.     /* Draw the arrow as an XfeButton would */
  734.     else
  735.     {
  736.         XfeDrawArrow(XtDisplay(w),
  737.                      _XfePrimitiveDrawable(w),
  738.                      _XfeLabelGetLabelGC(w),
  739.                      cp->cascade_arrow_rect.x + offset,
  740.                      cp->cascade_arrow_rect.y + offset,
  741.                      cp->cascade_arrow_rect.width,
  742.                      cp->cascade_arrow_rect.height,
  743.                      cp->cascade_arrow_direction);
  744.     }
  745. }
  746. /*----------------------------------------------------------------------*/
  747. static void
  748. LayoutCascadeArrow(Widget w)
  749. {
  750.     XfeCascadePart *        cp = _XfeCascadePart(w);
  751.     XfeButtonPart *            bp = _XfeButtonPart(w);
  752.     XRectangle                bound;
  753.  
  754.     /* Make sure the cascade arrow has some dimensions */
  755.     if (!cp->cascade_arrow_rect.height || !cp->cascade_arrow_rect.width)
  756.     {
  757.         return;
  758.     }
  759.  
  760.     /* If the button layout has a pixmap, place the arrow there */
  761.     if ((bp->button_layout != XmBUTTON_LABEL_ONLY) &&
  762.         bp->pixmap_rect.width && bp->pixmap_rect.height)
  763.     {
  764.         XfeRectSet(&bound,
  765.                    bp->pixmap_rect.x,
  766.                    bp->pixmap_rect.y,
  767.                    bp->pixmap_rect.width,
  768.                    bp->pixmap_rect.height);
  769.     }
  770.     else
  771.     {
  772.         XfeRectSet(&bound,
  773.                    _XfeRectX(w),
  774.                    _XfeRectY(w),
  775.                    _XfeRectWidth(w),
  776.                    _XfeRectHeight(w));
  777.     }
  778.  
  779.     /* Determine the horizontal layout of the arrow */
  780.     switch(cp->cascade_arrow_location)
  781.     {
  782.  
  783.     case XmLOCATION_NORTH_EAST:
  784.     case XmLOCATION_SOUTH_EAST:
  785.     case XmLOCATION_EAST:
  786.  
  787.         cp->cascade_arrow_rect.x = bound.x - cp->cascade_arrow_rect.width;
  788.  
  789.         break;
  790.  
  791.     case XmLOCATION_NORTH:
  792.     case XmLOCATION_SOUTH:
  793.  
  794.         cp->cascade_arrow_rect.x = 
  795.             (bound.width - cp->cascade_arrow_rect.width) / 2 +
  796.             bound.x;
  797.  
  798.         break;
  799.  
  800.     case XmLOCATION_SOUTH_WEST:
  801.     case XmLOCATION_WEST:
  802.     case XmLOCATION_NORTH_WEST:
  803.  
  804.         cp->cascade_arrow_rect.x = 
  805.             bound.width - cp->cascade_arrow_rect.width +
  806.             bound.x;
  807.  
  808.         break;
  809.  
  810.     }
  811.  
  812.     /* Determine the vertical layout of the arrow */
  813.     switch(cp->cascade_arrow_location)
  814.     {
  815.     case XmLOCATION_NORTH:
  816.     case XmLOCATION_NORTH_EAST:
  817.     case XmLOCATION_NORTH_WEST:
  818.  
  819.         cp->cascade_arrow_rect.y = 
  820.             bound.y;
  821.  
  822.         break;
  823.  
  824.     case XmLOCATION_EAST:
  825.     case XmLOCATION_WEST:
  826.  
  827.         cp->cascade_arrow_rect.y = 
  828.             (bound.height - cp->cascade_arrow_rect.height) / 2 +
  829.             bound.y;
  830.  
  831.         break;
  832.  
  833.     case XmLOCATION_SOUTH:
  834.     case XmLOCATION_SOUTH_EAST:
  835.     case XmLOCATION_SOUTH_WEST:
  836.  
  837.         cp->cascade_arrow_rect.y = 
  838.             bound.height - cp->cascade_arrow_rect.height +
  839.             bound.y;
  840.  
  841.         break;
  842.  
  843.     }
  844. }
  845. /*----------------------------------------------------------------------*/
  846. static void
  847. GetPostPosition(Widget w,Position * x_out,Position * y_out)
  848. {
  849.     XfeCascadePart *    cp = _XfeCascadePart(w);
  850.     XfeButtonPart *        bp = _XfeButtonPart(w);
  851.     Dimension            deco_offset;
  852.     Position            x;
  853.     Position            y;
  854.     Position            root_x = XfeRootX(w);
  855.     Position            root_y = XfeRootY(w);
  856.  
  857.     /* Position the menu below the button (like pulldown menus do) */
  858.     deco_offset = _XfeHighlightThickness(w);
  859.     
  860.     if (bp->raise_on_enter)
  861.     {
  862.         deco_offset += bp->raise_border_thickness;
  863.     }
  864.  
  865.     switch(cp->sub_menu_alignment)
  866.     {
  867.     case XmALIGNMENT_BEGINNING:
  868.  
  869.         x = root_x + deco_offset;
  870.  
  871.         break;
  872.         
  873.     case XmALIGNMENT_CENTER:
  874.  
  875.         x = root_x + (_XfeWidth(w) - _XfeWidth(cp->sub_menu_id)) / 2;
  876.  
  877.         break;
  878.  
  879.     case XmALIGNMENT_END:
  880.  
  881.         x = root_x + _XfeWidth(w) - _XfeWidth(cp->sub_menu_id) - deco_offset;
  882.             
  883.         break;
  884.     }
  885.     
  886.     y = root_y + _XfeHeight(w) - deco_offset;
  887.  
  888.     if (x_out)
  889.     {
  890.         *x_out = x;
  891.     }
  892.  
  893.     if (y_out)
  894.     {
  895.         *y_out = y;
  896.     }
  897. }
  898. /*----------------------------------------------------------------------*/
  899. static void
  900. InvokeTearCallback(Widget w,XEvent * event,Boolean torn)
  901. {
  902.     XfeCascadePart *    cp = _XfeCascadePart(w);
  903.  
  904.     /* Invoke the callbacks only if needed */
  905.     if (cp->submenu_tear_callback)
  906.     {
  907.         XfeSubmenuTearCallbackStruct cbs;
  908.         
  909.         cbs.event    = event;
  910.         cbs.reason    = XmCR_SUBMENU_TEAR;
  911.         cbs.torn    = torn;
  912.         
  913.         /* Flush the display */
  914.         XFlush(XtDisplay(w));
  915.         
  916.         /* Invoke the Callback List */
  917.         XtCallCallbackList(w,cp->submenu_tear_callback,&cbs);
  918.     }
  919. }
  920. /*----------------------------------------------------------------------*/
  921.  
  922. /*----------------------------------------------------------------------*/
  923. /*                                                                        */
  924. /* XfeCascade action procedures                                            */
  925. /*                                                                        */
  926. /*----------------------------------------------------------------------*/
  927. static void
  928. Arm(Widget w,XEvent * event,char ** params,Cardinal * nparams)
  929. {
  930.     XfeCascadePart *    cp = _XfeCascadePart(w);
  931.  
  932.     /* Make sure we are not insensitive (or pretending to be insensitive) */
  933.     if (!_XfeIsSensitive(w))
  934.     {
  935.         return;
  936.     }
  937.  
  938.     /* Make sure the submenu is not already posted */
  939.     if (cp->popped_up)
  940.     {
  941.         return;
  942.     }
  943.  
  944.     /* First, arm the button */
  945.     _XfeButtonArm(w,event,params,nparams);
  946.     
  947.     /* Invoke the cascading callback so that client can do magic */
  948.     _XfeInvokeCallbacks(w,cp->cascading_callback,XmCR_CASCADING,event,True);
  949.  
  950.     /* make sure the submenu has some children before posting */
  951.     if (!_XfemNumChildren(cp->sub_menu_id))
  952.     {
  953.         return;
  954.     }
  955.  
  956.     /* Make sure the submenu is not torn */
  957.     if (cp->torn)
  958.     {
  959.         return;
  960.     }
  961.  
  962.     /* Make sure no other timer is active.  If there is, remove it */
  963.     if (cp->delay_timer_id)
  964.     {
  965.         XtRemoveTimeOut(cp->delay_timer_id);
  966.         
  967.         cp->delay_timer_id = 0;
  968.     }
  969.  
  970.     /* Install the mapping delay timer if needed */
  971.     if (cp->mapping_delay)
  972.     {
  973.         XtVaSetValues(cp->sub_menu_id,XmNmenuPost,POPUP_ACCEPT,NULL);
  974.     
  975.         cp->delay_timer_id = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
  976.                                              cp->mapping_delay,
  977.                                              DelayTimeout,
  978.                                              (XtPointer) w);
  979.     }
  980.     /* If no mapping delay is given, post the submenu right away */
  981.     else
  982.     {
  983.         XtVaSetValues(cp->sub_menu_id,XmNmenuPost,POPUP_ACCEPT,NULL);
  984.         Post(w,event,NULL,0);
  985.     }
  986. }
  987. /*----------------------------------------------------------------------*/
  988. static void
  989. Activate(Widget w,XEvent * event,char ** params,Cardinal * nparams)
  990. {
  991.     XfeCascadePart *    cp = _XfeCascadePart(w);
  992.  
  993.     XtVaSetValues(cp->sub_menu_id,XmNmenuPost,POPUP_IGNORE,NULL);
  994.  
  995.     _XfeButtonActivate(w,event,params,nparams);
  996. }
  997. /*----------------------------------------------------------------------*/
  998. static void
  999. Disarm(Widget w,XEvent *event,char **params,Cardinal *nparams)
  1000. {
  1001.     XfeCascadePart *    cp = _XfeCascadePart(w);
  1002.  
  1003.     /* Make sure we are not insensitive (or pretending to be insensitive) */
  1004.     if (!_XfeIsSensitive(w))
  1005.     {
  1006.         return;
  1007.     }
  1008.  
  1009.     _XfeButtonDisarm(w,event,params,nparams);
  1010.  
  1011.     XtVaSetValues(cp->sub_menu_id,XmNmenuPost,POPUP_IGNORE,NULL);
  1012. }
  1013. /*----------------------------------------------------------------------*/
  1014. static void
  1015. Post(Widget w,XEvent * event,char ** params,Cardinal * nparams)
  1016. {
  1017.     XfeCascadePart *    cp = _XfeCascadePart(w);
  1018.  
  1019.     if (_XfeIsAlive(POPUP_SHELL(cp)) && _XfeIsAlive(cp->sub_menu_id))
  1020.     {
  1021.         XEvent *        the_event = event;
  1022.         Position        x;
  1023.         Position        y;
  1024.  
  1025.         if (!the_event)
  1026.         {
  1027.             XButtonEvent    be;
  1028.  
  1029.             /*
  1030.              * Hackery Hackery Hackery
  1031.              *
  1032.              * This crap occurs so that the menu can be posted programatically
  1033.              * in any context and not only button press which the motif popup
  1034.              * menus seem to expect.  I dont think all the given fields are
  1035.              * needed, but they are ther anyway.
  1036.              */
  1037.             be.type            = ButtonPress;
  1038.             be.serial        = 0;
  1039.             be.send_event    = 0;
  1040.             be.display        = XtDisplay(w);
  1041.              be.window        = _XfeWindow(w);
  1042.             be.root            = DefaultRootWindow(XtDisplay(w));
  1043.             be.subwindow    = None;
  1044.              be.time            = CurrentTime;
  1045.              be.state        = AnyModifier;
  1046.              be.button        = Button1;
  1047.             be.same_screen    = True;
  1048.  
  1049.             the_event = (XEvent *) &be;
  1050.         }
  1051.  
  1052.         assert( the_event != NULL );
  1053.  
  1054.         /*
  1055.          * Force the modifiers to any.  The motif row column - and thus 
  1056.          * popup menus, will not post correctly if either the ShiftMask
  1057.          * or LockMask bit is set in the button event modifier state.
  1058.          */
  1059.         if (the_event->type == ButtonPress)
  1060.         {
  1061.             the_event->xbutton.state = AnyModifier;
  1062.         }
  1063.  
  1064.         /* Find out where the sub menu is supposed to post */
  1065.         GetPostPosition(w,&x,&y);
  1066.  
  1067.         /* Position the sub menu */
  1068.         XfeMenuPositionXY(cp->sub_menu_id,x,y);
  1069.  
  1070.         /* Make sure the submenu is realized */
  1071.         if (!XtIsRealized(cp->sub_menu_id))
  1072.         {
  1073.             XtRealizeWidget(cp->sub_menu_id);
  1074.         }
  1075.  
  1076.         /* Synchronize and flush the display before popping up the submenu */
  1077.         XSync(XtDisplay(w),False);
  1078.  
  1079.         XmUpdateDisplay(w);
  1080.  
  1081.         /* Post the button */
  1082.         _XmPostPopupMenu(cp->sub_menu_id,the_event);
  1083.     }
  1084. }
  1085. /*----------------------------------------------------------------------*/
  1086. static void
  1087. Unpost(Widget w,XEvent *event,char **params,Cardinal *nparams)
  1088. {
  1089.     XfeCascadePart *    cp = _XfeCascadePart(w);
  1090.  
  1091.     if (_XfeIsAlive(XtParent(cp->sub_menu_id)) && _XfeIsAlive(cp->sub_menu_id))
  1092.     {
  1093.         XtUnmanageChild(cp->sub_menu_id);
  1094.     }
  1095. }
  1096. /*----------------------------------------------------------------------*/
  1097.  
  1098. /*----------------------------------------------------------------------*/
  1099. /*                                                                        */
  1100. /* SubMenu event handlers and callbacks                                    */
  1101. /*                                                                        */
  1102. /*----------------------------------------------------------------------*/
  1103. static void
  1104. SubMenuEH(Widget        shell,
  1105.           XtPointer        client_data,
  1106.           XEvent *        event,
  1107.           Boolean *        cont)
  1108. {
  1109.     Widget                w = (Widget) client_data;
  1110.     XfeCascadePart *    cp = _XfeCascadePart(w);
  1111.  
  1112.     switch (event->type) 
  1113.     {
  1114.     case MapNotify:
  1115.  
  1116.         XtVaSetValues(cp->sub_menu_id,XmNmenuPost,POPUP_IGNORE,NULL);
  1117.  
  1118.         /* Submenu is now popped up */
  1119.         cp->popped_up = True;
  1120.  
  1121.         /* Invoke the popup callbacks */
  1122.         _XfeInvokeCallbacks(w,cp->popup_callback,XmCR_POPUP,event,True);
  1123.  
  1124.         break;
  1125.  
  1126.     case UnmapNotify:
  1127.  
  1128.         Disarm(w,NULL,NULL,0);
  1129.         
  1130.         XtVaSetValues(cp->sub_menu_id,XmNmenuPost,POPUP_IGNORE,NULL);
  1131.  
  1132.         /* Submenu is now popped down */
  1133.         cp->popped_up = False;
  1134.  
  1135.         /* Invoke the popdown callbacks */
  1136.         _XfeInvokeCallbacks(w,cp->popdown_callback,XmCR_POPDOWN,event,True);
  1137.  
  1138.         break;
  1139.     }
  1140. }
  1141. /*----------------------------------------------------------------------*/
  1142. static void
  1143. SubMenuTearCB(Widget menu,XtPointer client_data,XtPointer call_data)
  1144. {
  1145.     XmRowColumnCallbackStruct * cbs = (XmRowColumnCallbackStruct *) call_data;
  1146.     Widget                        w = (Widget) client_data;
  1147.     XfeCascadePart *            cp = _XfeCascadePart(w);
  1148.  
  1149.     if (cbs->reason == XmCR_TEAR_OFF_ACTIVATE)
  1150.     {
  1151.         cp->torn = True;
  1152.     }
  1153.     else if (cbs->reason == XmCR_TEAR_OFF_DEACTIVATE)
  1154.     {
  1155.         cp->torn = False;
  1156.     }
  1157.  
  1158.     InvokeTearCallback(w,cbs->event,cp->torn);
  1159. }
  1160. /*----------------------------------------------------------------------*/
  1161. static void
  1162. UnGrabEH(Widget            shell,
  1163.          XtPointer        client_data,
  1164.          XEvent *        event,
  1165.          Boolean *        cont)
  1166. {
  1167.     Widget                w = (Widget) client_data;
  1168.     XfeCascadePart *    cp = _XfeCascadePart(w);
  1169.     
  1170.     if ((event->type == ButtonPress) && (event->xbutton.button >= Button2))
  1171.     {
  1172.         XtUngrabPointer(cp->sub_menu_id,CurrentTime);
  1173.     }
  1174. }
  1175. /*----------------------------------------------------------------------*/
  1176.  
  1177. /*----------------------------------------------------------------------*/
  1178. /*                                                                        */
  1179. /* XfeCascade Public Methods                                            */
  1180. /*                                                                        */
  1181. /*----------------------------------------------------------------------*/
  1182. Widget
  1183. XfeCreateCascade(Widget parent,char *name,Arg *args,Cardinal count)
  1184. {
  1185.     return (XtCreateWidget(name,xfeCascadeWidgetClass,parent,args,count));
  1186. }
  1187. /*----------------------------------------------------------------------*/
  1188. /* extern */ void
  1189. XfeCascadeDestroyChildren(Widget w)
  1190. {
  1191.     XfeCascadePart *    cp = _XfeCascadePart(w);
  1192.  
  1193.     assert( _XfeIsAlive(w) );
  1194.     assert( XfeIsCascade(w) );
  1195.     assert( _XfeIsAlive(cp->sub_menu_id) );
  1196.  
  1197.     XfeChildrenDestroy(cp->sub_menu_id);
  1198. }
  1199. /*----------------------------------------------------------------------*/
  1200. /* extern */ Boolean
  1201. XfeCascadeArmAndPost(Widget w,XEvent *    event)
  1202. {
  1203.     XfeCascadePart *    cp = _XfeCascadePart(w);
  1204.  
  1205.     assert( _XfeIsAlive(w) );
  1206.     assert( XfeIsCascade(w) );
  1207.     assert( _XfeIsAlive(cp->sub_menu_id) );
  1208.  
  1209.     /* Make sure the subment is not already popped up or torn */
  1210.     if (!cp->popped_up && 
  1211.         !cp->torn && 
  1212.         _XfeIsAlive(POPUP_SHELL(cp)) && 
  1213.         _XfeIsAlive(cp->sub_menu_id))
  1214.     {
  1215.         Arm(w,event,NULL,0);
  1216.         Post(w,event,NULL,0);
  1217.  
  1218.         return True;
  1219.     }
  1220.  
  1221.  
  1222.     return False;
  1223. }
  1224. /*----------------------------------------------------------------------*/
  1225. /* extern */ Boolean
  1226. XfeCascadeDisarmAndUnpost(Widget w,XEvent *    event)
  1227. {
  1228.     XfeCascadePart *    cp = _XfeCascadePart(w);
  1229.  
  1230.     assert( _XfeIsAlive(w) );
  1231.     assert( XfeIsCascade(w) );
  1232.     assert( _XfeIsAlive(cp->sub_menu_id) );
  1233.  
  1234.     /* Make sure the subment is not already popped up or torn */
  1235.     if (cp->popped_up)
  1236.     {
  1237.         Disarm(w,event,NULL,0);
  1238.         Unpost(w,event,NULL,0);
  1239.         
  1240.         return True;
  1241.     }
  1242.     
  1243.     return False;
  1244. }
  1245. /*----------------------------------------------------------------------*/
  1246. /* extern */ void
  1247. XfeCascadeGetChildren(Widget w,WidgetList * children,Cardinal * num_children)
  1248. {
  1249.     XfeCascadePart *    cp = _XfeCascadePart(w);
  1250.  
  1251.     assert( _XfeIsAlive(w) );
  1252.     assert( XfeIsCascade(w) );
  1253.     assert( _XfeIsAlive(cp->sub_menu_id) );
  1254.     assert( children != NULL || num_children != NULL );
  1255.  
  1256.  
  1257.     if (_XfeIsAlive(w) && _XfeIsAlive(cp->sub_menu_id))
  1258.     {
  1259.         *children = _XfemChildren(cp->sub_menu_id);
  1260.         *num_children = _XfemNumChildren(cp->sub_menu_id);
  1261.     }
  1262.     else
  1263.     {
  1264.         *children = NULL;
  1265.         *num_children = 0;
  1266.     }
  1267. }
  1268. /*----------------------------------------------------------------------*/
  1269.