"Fossies" - the Fresh Open Source Software Archive

Member "jed-0.99-19/src/menu.c" (14 Dec 2009, 54048 Bytes) of package /linux/misc/jed-0.99-19.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "menu.c" see the Fossies "Dox" file reference documentation.

    1 /* Drop-down menus (tty) */
    2 /* Copyright (c) 1999, 2000, 2002-2009 John E. Davis
    3  * This file is part of JED editor library source.
    4  *
    5  * You may distribute this file under the terms the GNU General Public
    6  * License.  See the file COPYING for more information.
    7  */
    8 #include "config.h"
    9 #include "jed-feat.h"
   10 
   11 #include <stdio.h>
   12 #if JED_HAS_MENUS
   13 
   14 #include <slang.h>
   15 
   16 #include "jdmacros.h"
   17 
   18 #include <string.h>
   19 
   20 #include "buffer.h"
   21 #include "screen.h"
   22 #include "misc.h"
   23 #include "sysdep.h"
   24 #include "cmds.h"
   25 #include "menu.h"
   26 #include "colors.h"
   27 
   28 typedef struct _Menu_Node_Type
   29 {
   30    char *name;
   31    int type;
   32 #define MENU_NODE_FUN_SLANG 1
   33 #define MENU_NODE_FUN_C     2
   34 #define MENU_NODE_POPUP     3
   35 #define MENU_NODE_SEPARATOR 4
   36 #define MENU_NODE_MENUBAR   5
   37 #define MENU_NODE_KEYSTRING 6
   38 
   39    unsigned int flags;
   40 #define MENU_ACTIVE     1
   41 #define MENU_SELECTION      2
   42 #define MENU_ITEM_UNAVAILABLE   4
   43 #define MENU_POPUP_PREPARED 8
   44 }
   45 Menu_Node_Type;
   46 
   47 typedef struct _Menu_Popup_Type
   48 {
   49    char *name;
   50    int type;                   /* =MENU_NODE */
   51    unsigned int flags;
   52 
   53    /* Private data */
   54    /* These 5 must match Menu_Bar_Type */
   55    Menu_Node_Type **subnodes;
   56    unsigned int num_subnodes;
   57    unsigned int max_subnodes;
   58    struct _Menu_Popup_Type *parent;
   59    unsigned int active_node;
   60 
   61    SLang_Name_Type *select_popup_callback;
   62    SLang_Name_Type *tweak_popup_callback;
   63 
   64    int column;                 /* meaningful when active */
   65    int row;
   66    int max_row;
   67    int max_col;
   68    unsigned int min_width;
   69    int visible_node_offset;
   70 }
   71 Menu_Popup_Type;
   72 
   73 struct _Menu_Bar_Type
   74 {
   75    char *name;
   76    int type;                   /* =MENU_NODE */
   77    unsigned int flags;
   78    
   79    /* Private data */
   80    /* These 5 must match Menu_Popup_Type */
   81    Menu_Node_Type **subnodes;
   82    unsigned int num_subnodes;
   83    unsigned int max_subnodes;   
   84    struct _Menu_Popup_Type *parent;   
   85    unsigned int active_node;
   86 
   87    SLang_Name_Type *init_callback;
   88    SLang_Name_Type *select_callback;   /* Void select_callback (name) */
   89 
   90    int *item_columns;          /* locations of items on menu bar */
   91    unsigned int num_refs;
   92 
   93 #define DEFAULT_MENU_PREFIX "F10 key ==> "
   94    char *prefix_string;
   95    struct _Menu_Bar_Type *next;
   96 };
   97 
   98 typedef struct
   99 {
  100    char *name;
  101    int type;
  102    unsigned int flags;
  103 
  104    SLang_Name_Type *slang_fun;
  105    SLang_Any_Type *client_data;
  106 }
  107 Menu_SLang_Fun_Type;
  108 
  109 typedef struct
  110 {
  111    char *name;
  112    int type;
  113    unsigned int flags;
  114 
  115    int (*c_fun)(void);
  116 }
  117 Menu_C_Fun_Type;
  118 
  119 typedef struct
  120 {
  121    char *name;
  122    int type;
  123    unsigned int flags;
  124    
  125    char *keystring;
  126 }
  127 Menu_Keystring_Fun_Type;
  128 
  129 int Jed_Menus_Active;
  130 
  131 static Menu_Bar_Type *Global_Menu_Bar;
  132 static Menu_Bar_Type *Menu_Bar_Root;
  133 static Menu_Bar_Type *Active_Menu_Bar;
  134 static Menu_Popup_Type *Active_Popup;
  135 
  136 static void free_menu_node (Menu_Node_Type *);
  137 static int select_menu_cmd (void);
  138 
  139 static void free_menu_popup_subnodes (Menu_Popup_Type *m)
  140 {
  141    Menu_Node_Type **l, **lmax;
  142 
  143    l = m->subnodes;
  144    lmax = l + m->num_subnodes;
  145 
  146    while (l < lmax)
  147      {
  148     free_menu_node (*l);
  149     l++;
  150      }
  151    SLfree ((char *) m->subnodes);
  152 
  153    m->subnodes = NULL;
  154    m->num_subnodes = 0;
  155    m->max_subnodes = 0;
  156 }
  157 
  158 
  159 static void free_menu_popup_private_data (Menu_Popup_Type *m)
  160 {
  161    free_menu_popup_subnodes (m);
  162 #if SLANG_VERSION > 10400
  163    SLang_free_function (m->select_popup_callback);
  164    SLang_free_function (m->tweak_popup_callback);
  165    m->select_popup_callback = NULL;
  166    m->tweak_popup_callback = NULL;
  167 #endif
  168 }
  169 
  170 static void free_menu_bar_private_data (Menu_Bar_Type *m)
  171 {
  172    Menu_Node_Type **l, **lmax;
  173 
  174    if (m == Active_Menu_Bar)
  175      Active_Menu_Bar = NULL;
  176 
  177    if (m == Global_Menu_Bar)
  178      Global_Menu_Bar = NULL;
  179 
  180    if (m == Menu_Bar_Root)
  181      Menu_Bar_Root = m->next;
  182    else
  183      {
  184     Menu_Bar_Type *prev;
  185     
  186     prev = Menu_Bar_Root;
  187     while (prev->next != m)
  188       prev = prev->next;
  189     
  190     prev->next = m->next;
  191      }
  192 
  193    l = m->subnodes;
  194    lmax = l + m->num_subnodes;
  195 
  196    while (l < lmax)
  197      {
  198     free_menu_node (*l);
  199     l++;
  200      }
  201    SLfree ((char *) m->subnodes);
  202    SLfree ((char *) m->item_columns);
  203    SLang_free_slstring (m->prefix_string);
  204 #if SLANG_VERSION > 10400
  205    SLang_free_function (m->init_callback);
  206    SLang_free_function (m->select_callback);
  207 #endif
  208 
  209 }
  210 
  211 static void free_keystring_private_data (Menu_Keystring_Fun_Type *m)
  212 {
  213    SLang_free_slstring (m->keystring);
  214 }
  215 
  216 static void free_slangfun_private_data (Menu_SLang_Fun_Type *m)
  217 {
  218    if (m->client_data != NULL)
  219      SLang_free_anytype (m->client_data);
  220 #if SLANG_VERSION > 10400
  221    SLang_free_function (m->slang_fun);
  222 #endif
  223 }
  224 
  225 static void free_menu_node (Menu_Node_Type *m)
  226 {
  227    Menu_Bar_Type *b;
  228 
  229    if (m == NULL)
  230      return;
  231 
  232    switch (m->type)
  233      {
  234       case MENU_NODE_SEPARATOR:
  235       case MENU_NODE_FUN_C:
  236     break;
  237 
  238       case MENU_NODE_FUN_SLANG:
  239     free_slangfun_private_data ((Menu_SLang_Fun_Type *) m);
  240     break;
  241 
  242       case MENU_NODE_KEYSTRING:
  243     free_keystring_private_data ((Menu_Keystring_Fun_Type *) m);
  244     break;
  245 
  246       case MENU_NODE_MENUBAR:
  247     b = (Menu_Bar_Type *)m;
  248     if (b->num_refs > 1)
  249       {
  250          b->num_refs -= 1;
  251          return;
  252       }
  253     free_menu_bar_private_data ((Menu_Bar_Type *) m);
  254     break;
  255 
  256       case MENU_NODE_POPUP:
  257     free_menu_popup_private_data ((Menu_Popup_Type *) m);
  258     break;
  259      }
  260 
  261    SLang_free_slstring (m->name);
  262    SLfree ((char *) m);
  263 }
  264 
  265 static Menu_Node_Type *create_menu_node (char *name, int node_type,
  266                      unsigned int sizeof_node)
  267 {
  268    Menu_Node_Type *m;
  269 
  270    m = (Menu_Node_Type *) jed_malloc0 (sizeof_node);
  271    if (m == NULL)
  272      return NULL;
  273 
  274    m->type = node_type;
  275    
  276    if (NULL == (m->name = SLang_create_slstring (name)))
  277      {
  278     SLfree ((char *)m);
  279     return NULL;
  280      }
  281    
  282    return m;
  283 }
  284 
  285 
  286 static Menu_Popup_Type *create_menu_popup (char *name, unsigned int num_items)
  287 {
  288    Menu_Popup_Type *m;
  289    
  290    m = (Menu_Popup_Type *) create_menu_node (name, MENU_NODE_POPUP, sizeof (Menu_Popup_Type));
  291    if (m == NULL)
  292      return NULL;
  293 
  294    if (num_items == 0)
  295      num_items = 5;
  296    
  297    if (NULL == (m->subnodes = (Menu_Node_Type **)SLmalloc (num_items * sizeof (Menu_Node_Type *))))
  298      {
  299     free_menu_node ((Menu_Node_Type *) m);
  300     return NULL;
  301      }
  302    m->max_subnodes = num_items;
  303    return m;
  304 }
  305 
  306 
  307 static Menu_Bar_Type *create_menu_bar (char *name, unsigned int num_items)
  308 {
  309    Menu_Bar_Type *m;
  310    char *prefix;
  311 
  312    m = (Menu_Bar_Type *) create_menu_node (name, MENU_NODE_MENUBAR, sizeof (Menu_Bar_Type));
  313    if (m == NULL)
  314      return NULL;
  315 
  316    if (num_items == 0)
  317      num_items = 5;
  318 
  319    if ((NULL == (m->subnodes = (Menu_Node_Type **)SLmalloc (num_items * sizeof (Menu_Node_Type *))))
  320        || (NULL == (m->item_columns = (int *)jed_malloc0 (num_items * sizeof (int)))))
  321      {
  322     free_menu_node ((Menu_Node_Type *) m);
  323     return NULL;
  324      }
  325 
  326    m->max_subnodes = num_items;
  327 
  328    if (Menu_Bar_Root != NULL)
  329      m->next = Menu_Bar_Root;
  330    Menu_Bar_Root = m;
  331 
  332    m->num_refs = 1;
  333    
  334    prefix = DEFAULT_MENU_PREFIX;
  335    if ((Global_Menu_Bar != NULL)
  336        && (Global_Menu_Bar->prefix_string != NULL))
  337      prefix = Global_Menu_Bar->prefix_string;
  338    
  339    prefix = SLang_create_slstring (prefix);
  340    if (prefix == NULL)
  341      {
  342     jed_delete_menu_bar (m);
  343     return NULL;
  344      }
  345    m->prefix_string = prefix;
  346 
  347    return m;
  348 }
  349 
  350 void jed_delete_menu_bar (Menu_Bar_Type *m)
  351 {
  352    if (m == NULL)
  353      return;
  354 
  355    free_menu_node ((Menu_Node_Type *)m);
  356 }
  357 
  358 
  359 static int menu_name_eqs (char *a, char *b, char *bmax)
  360 {
  361    while (*a)
  362      {
  363     if ((b == bmax)
  364         || (*a != *b))
  365       return 0;
  366     
  367     a++;
  368     b++;
  369      }
  370    
  371    return (b == bmax);
  372 }
  373 
  374 static Menu_Bar_Type *menu_find_menu_bar (char *name, int do_error)
  375 {
  376    Menu_Bar_Type *b;
  377    char *name_max;
  378 
  379    name_max = strchr (name, '.');
  380    if (name_max == NULL)
  381      name_max = name + strlen (name);
  382 
  383    b = Menu_Bar_Root;
  384    while (b != NULL)
  385      {
  386     if (menu_name_eqs (b->name, name, name_max))
  387       return b;
  388 
  389     b = b->next;
  390      }
  391 
  392    if (do_error)
  393      SLang_verror (SL_INTRINSIC_ERROR, 
  394            "Unable to a find menu bar called %s", 
  395            name);
  396    return NULL;
  397 }
  398 
  399 
  400 static Menu_Node_Type *find_subnode (Menu_Popup_Type *m, char *name)
  401 {
  402    Menu_Node_Type **l, **lmax;
  403 
  404    if (m == NULL)
  405      return NULL;
  406    
  407    l = m->subnodes;
  408    lmax = l + m->num_subnodes;
  409    
  410    while (l < lmax)
  411      {
  412     if (0 == strcmp (name, (*l)->name))
  413       return *l;
  414     
  415     l++;
  416      }
  417    return NULL;
  418 }
  419 
  420 
  421 static int check_subnode_space (Menu_Popup_Type *m, unsigned int dn)
  422 {
  423    Menu_Node_Type **subnodes;
  424    unsigned int num;
  425 
  426    if (m->num_subnodes + dn <= m->max_subnodes)
  427      return 0;
  428 
  429    num = m->max_subnodes + dn;
  430 
  431    subnodes = (Menu_Node_Type **)SLrealloc ((char *)m->subnodes, num * sizeof (Menu_Node_Type *));
  432    if (subnodes == NULL)
  433      return -1;
  434    m->subnodes = subnodes;
  435 
  436    if (m->type == MENU_NODE_MENUBAR)
  437      {
  438     Menu_Bar_Type *b = (Menu_Bar_Type *)m;
  439     int *item_columns;
  440     unsigned int i;
  441 
  442     item_columns = (int *)SLrealloc ((char *)b->item_columns, num * sizeof(int));
  443     if (item_columns == NULL)
  444       return -1;
  445     
  446     for (i = m->max_subnodes; i < num; i++)
  447       item_columns [i] = 0;
  448     b->item_columns = item_columns;
  449      }
  450 
  451    m->max_subnodes = num;
  452    return 0;
  453 }
  454 
  455 /* This function assumes that there is enough space to insert one item */
  456 static void insert_node_to_popup (Menu_Popup_Type *p, Menu_Node_Type *m, 
  457                   unsigned int where)
  458 {
  459    unsigned int len;
  460    unsigned int n;
  461    
  462    n = p->num_subnodes;
  463 
  464    if (where > n)
  465      where = n;
  466 
  467    while (n > where)
  468      {
  469     p->subnodes[n] = p->subnodes[n-1];
  470     n--;
  471      }
  472    p->subnodes[where]  = m;
  473    p->num_subnodes += 1;
  474 
  475    /* p could be a menu-bar */
  476 
  477    if (p->type != MENU_NODE_POPUP)
  478      return;
  479 
  480    len = strlen (m->name);
  481    if (len > p->min_width)
  482      p->min_width = len;
  483 }
  484 
  485 #if 0
  486 static void append_node_to_popup (Menu_Popup_Type *p, Menu_Node_Type *m)
  487 {
  488    insert_node_to_popup (p, m, p->num_subnodes);
  489 }
  490 #endif
  491    
  492 static Menu_Popup_Type *insert_popup_menu (Menu_Popup_Type *m, char *name, int where)
  493 {
  494    Menu_Popup_Type *p;
  495 
  496    if (NULL != (p = (Menu_Popup_Type *)find_subnode (m, name)))
  497      return p;
  498 
  499    if (-1 == check_subnode_space (m, 1))
  500      return NULL;
  501 
  502    p = create_menu_popup (name, 5);
  503    if (p == NULL)
  504      return NULL;
  505    
  506    p->parent = m;
  507    
  508    insert_node_to_popup (m, (Menu_Node_Type *)p, where);
  509    return p;
  510 }
  511 
  512 static Menu_Popup_Type *append_popup_menu (Menu_Popup_Type *m, char *name)
  513 {
  514    return insert_popup_menu (m, name, m->num_subnodes);
  515 }
  516 
  517 
  518 static Menu_Node_Type *insert_separator (Menu_Popup_Type *m, int where)
  519 {
  520    Menu_Node_Type *l;
  521 
  522    if (-1 == check_subnode_space (m, 1))
  523      return NULL;
  524 
  525    l = create_menu_node ("", MENU_NODE_SEPARATOR, sizeof (Menu_Node_Type));
  526    if (l == NULL)
  527      return NULL;
  528 
  529    insert_node_to_popup (m, l, where);
  530 
  531    return l;
  532 }
  533 
  534 static Menu_Node_Type *append_separator (Menu_Popup_Type *m)
  535 {
  536    return insert_separator (m, m->num_subnodes);
  537 }
  538 
  539 
  540 static Menu_SLang_Fun_Type *insert_slang_fun_item (Menu_Popup_Type *m, char *name, 
  541                            SLang_Name_Type *nt, SLang_Any_Type *cd,
  542                            int where)
  543 {
  544    Menu_SLang_Fun_Type *l;
  545 
  546    if (NULL != (l = (Menu_SLang_Fun_Type *)find_subnode (m, name)))
  547      {
  548     if (l->type != MENU_NODE_FUN_SLANG)
  549       return NULL;
  550 
  551     free_slangfun_private_data (l);
  552     l->slang_fun = nt;
  553     l->client_data = cd;
  554     
  555     return l;
  556      }
  557 
  558    if (-1 == check_subnode_space (m, 1))
  559      return NULL;
  560 
  561    l = (Menu_SLang_Fun_Type *)
  562      create_menu_node (name, MENU_NODE_FUN_SLANG, sizeof (Menu_SLang_Fun_Type));
  563 
  564    if (l == NULL)
  565      return NULL;
  566 
  567    l->slang_fun = nt;
  568    l->client_data = cd;
  569 
  570    insert_node_to_popup (m, (Menu_Node_Type *)l, where);
  571    return l;
  572 }
  573 
  574 static Menu_SLang_Fun_Type *append_slang_fun_item (Menu_Popup_Type *m, char *name,
  575                            SLang_Name_Type *nt, SLang_Any_Type *cd)
  576 {
  577    return insert_slang_fun_item (m, name, nt, cd, m->num_subnodes);
  578 }
  579 
  580 static Menu_Keystring_Fun_Type *insert_keystring_item (Menu_Popup_Type *m, char *name, 
  581                                char *k, int where)
  582 {
  583    Menu_Keystring_Fun_Type *l;
  584 
  585    if (NULL != (l = (Menu_Keystring_Fun_Type *)find_subnode (m, name)))
  586      {
  587     if (l->type != MENU_NODE_KEYSTRING)
  588       return NULL;
  589     
  590     if (NULL == (k = SLang_create_slstring (k)))
  591       return NULL;
  592 
  593     free_keystring_private_data (l);
  594     l->keystring = k;
  595     return l;
  596      }
  597 
  598 
  599    if (-1 == check_subnode_space (m, 1))
  600      return NULL;
  601 
  602    l = (Menu_Keystring_Fun_Type *)
  603      create_menu_node (name, MENU_NODE_KEYSTRING, sizeof (Menu_Keystring_Fun_Type));
  604 
  605    if (l == NULL)
  606      return NULL;
  607 
  608    if (NULL == (l->keystring = SLang_create_slstring (k)))
  609      {
  610     free_menu_node ((Menu_Node_Type *) l);
  611     return NULL;
  612      }
  613 
  614    insert_node_to_popup (m, (Menu_Node_Type *)l, where);
  615    return l;
  616 }
  617 
  618 static Menu_Keystring_Fun_Type *append_keystring_item (Menu_Popup_Type *m, char *name, char *k)
  619 {
  620    return insert_keystring_item (m, name, k, m->num_subnodes);
  621 }
  622 
  623 static Menu_Node_Type *get_selected_menu_item (Menu_Popup_Type *p)
  624 {
  625    Menu_Node_Type *m;
  626 
  627    if (p == NULL)
  628      return NULL;
  629 
  630    if (p->num_subnodes <= p->active_node)
  631      {
  632     p->active_node = 0;
  633     return NULL;
  634      }
  635 
  636    m = p->subnodes[p->active_node];
  637    if (m->flags & MENU_ITEM_UNAVAILABLE)
  638      {
  639     p->active_node = 0;
  640     return NULL;
  641      }
  642 
  643    /* Make sure this is selected. */
  644    m->flags |= MENU_SELECTION;
  645    return m;
  646 }
  647 
  648 static int unselect_active_node (Menu_Popup_Type *b)
  649 {
  650    Menu_Node_Type *m;
  651    
  652    if (NULL == (m = get_selected_menu_item (b)))
  653      return -1;
  654 
  655    m->flags &= ~(MENU_SELECTION|MENU_ACTIVE);
  656    return 0;
  657 }
  658 
  659 static int select_next_active_node (Menu_Popup_Type *b, unsigned int active_node,
  660                     unsigned int flags)
  661 {
  662    int wrapped;
  663    unsigned int num_subnodes;
  664 
  665    if (b == NULL)
  666      return -1;
  667 
  668    num_subnodes = b->num_subnodes;
  669 
  670    if (num_subnodes == 0)
  671      {
  672     b->active_node = 0;
  673     return -1;
  674      }
  675 
  676    unselect_active_node (b);
  677 
  678    wrapped = 0;
  679 
  680    while (1)
  681      {
  682     Menu_Node_Type *node;
  683 
  684     active_node++;
  685     if (active_node >= num_subnodes)
  686       {
  687          active_node = 0;
  688          if (wrapped)
  689            return -1;
  690 
  691          wrapped = 1;
  692       }
  693 
  694     node = b->subnodes[active_node];
  695     if ((node->type != MENU_NODE_SEPARATOR)
  696         && (0 == (node->flags & MENU_ITEM_UNAVAILABLE)))
  697       {
  698          node->flags |= MENU_SELECTION|flags;
  699          break;
  700       }
  701      }
  702 
  703    b->active_node = active_node;
  704    return 0;
  705 }
  706 
  707 static int select_prev_active_node (Menu_Popup_Type *b, unsigned int active_node,
  708                     unsigned int flags)
  709 {
  710    int wrapped;
  711    unsigned int num_subnodes;
  712 
  713    if (b == NULL)
  714      return -1;
  715 
  716    num_subnodes = b->num_subnodes;
  717 
  718    if (num_subnodes == 0)
  719      {
  720     b->active_node = 0;
  721     return -1;
  722      }
  723 
  724    unselect_active_node (b);
  725 
  726    wrapped = 0;
  727 
  728    while (1)
  729      {
  730     Menu_Node_Type *node;
  731 
  732     if (active_node == 0)
  733       {
  734          active_node = num_subnodes;
  735          if (wrapped)
  736            return -1;
  737          
  738          wrapped = 1;
  739       }
  740     active_node--;
  741 
  742     node = b->subnodes[active_node];
  743     if ((node->type != MENU_NODE_SEPARATOR)
  744         && (0 == (node->flags & MENU_ITEM_UNAVAILABLE)))
  745       {
  746          node->flags |= MENU_SELECTION|flags;
  747          break;
  748       }
  749      }
  750 
  751    b->active_node = active_node;
  752    return 0;
  753 }
  754 
  755 
  756 
  757 static int set_node_selection (Menu_Popup_Type *p, Menu_Node_Type *m)
  758 {  
  759    unsigned int i, imax;
  760    Menu_Node_Type **subnodes;
  761 
  762    if ((p == NULL) || (m == NULL)
  763        || (m->type == MENU_NODE_SEPARATOR)
  764        || (m->flags & MENU_ITEM_UNAVAILABLE))
  765      return -1;
  766 
  767    subnodes = p->subnodes;
  768    imax = p->num_subnodes;
  769    for (i = 0; i < imax; i++)
  770      {
  771     if (subnodes[i] == m)
  772       {
  773          unselect_active_node (p);
  774          p->active_node = i;
  775          m->flags |= MENU_SELECTION;
  776          return 0;
  777       }
  778      }
  779    return -1;
  780 }
  781 
  782    
  783 static unsigned int get_active_node_flags (Menu_Popup_Type *p)
  784 {
  785    Menu_Node_Type *m;
  786    
  787    m = get_selected_menu_item (p);
  788    if (m == NULL)
  789      return 0;
  790    
  791    return m->flags;
  792 }
  793 
  794 static int menu_delete_node (Menu_Popup_Type *p, Menu_Node_Type *m)
  795 {
  796    unsigned int i, imax;
  797 
  798    if ((p == NULL) || (m == NULL))
  799      return -1;
  800    
  801    imax = p->num_subnodes;
  802    for (i = 0; i < imax; i++)
  803      {
  804     if (p->subnodes[i] != m)
  805       continue;
  806     
  807     if (i == p->active_node)
  808       p->active_node = 0;
  809     
  810     while (++i < imax)
  811       p->subnodes[i-1] = p->subnodes[i];
  812     
  813     p->num_subnodes -= 1;
  814     
  815     (void) unselect_active_node (p);
  816     free_menu_node (m);
  817     return 0;
  818      }
  819    return -1;
  820 }
  821 
  822 static int menu_delete_nodes (Menu_Popup_Type *p)
  823 {
  824    unsigned int i, imax;
  825 
  826    if (p == NULL)
  827      return -1;
  828 
  829    imax = p->num_subnodes;
  830    for (i = 0; i < imax; i++)
  831      free_menu_node (p->subnodes[i]);
  832 
  833    p->num_subnodes = 0;
  834    p->active_node = 0;
  835    return 0;
  836 }
  837 
  838 
  839 static int copy_menu (Menu_Popup_Type *dest, Menu_Node_Type *src)
  840 {
  841    Menu_Node_Type **l, **lmax;
  842    Menu_Popup_Type *p;
  843    Menu_Node_Type *m;
  844    SLang_Any_Type *any;
  845    Menu_SLang_Fun_Type *sl;
  846 
  847    if (src == (Menu_Node_Type *)dest)
  848      {
  849     SLang_verror (SL_INTRINSIC_ERROR,
  850               "Unable to copy a menu onto itself");
  851     return -1;
  852      }
  853 
  854    switch (src->type)
  855      {
  856       case MENU_NODE_POPUP:
  857     p = (Menu_Popup_Type *) src;
  858     l = p->subnodes;
  859     lmax = l + p->num_subnodes;
  860     
  861     p = append_popup_menu (dest, src->name);
  862     if (p == NULL)
  863       return -1;
  864     
  865     while (l < lmax)
  866       {
  867          if (-1 == copy_menu (p, *l))
  868            {
  869           menu_delete_node (dest, (Menu_Node_Type *)p);
  870           return -1;
  871            }
  872          l++;
  873       }
  874     m = (Menu_Node_Type *)p;
  875     break;
  876     
  877       case MENU_NODE_SEPARATOR:
  878     m = append_separator (dest);
  879     break;
  880     
  881       case MENU_NODE_FUN_SLANG:
  882     sl = (Menu_SLang_Fun_Type *) src;
  883     /* Need a s-lang fun for this !!! */
  884     if ((-1 == SLang_push_anytype (sl->client_data))
  885         || (-1 == SLang_pop_anytype (&any)))
  886       return -1;
  887 
  888     m = (Menu_Node_Type *) append_slang_fun_item (dest, sl->name,
  889                                sl->slang_fun, any);
  890     if (m == NULL)
  891       SLang_free_anytype (any);
  892     break;
  893     
  894       case MENU_NODE_KEYSTRING:
  895     m = (Menu_Node_Type *) append_keystring_item (dest, src->name, ((Menu_Keystring_Fun_Type *)src)->keystring);
  896     break;
  897     
  898       case MENU_NODE_MENUBAR:
  899     SLang_verror (SL_INTRINSIC_ERROR, "Unable to copy a menu-bar");
  900     return -1;
  901 
  902       case MENU_NODE_FUN_C:
  903       default:
  904     SLang_verror (SL_APPLICATION_ERROR,
  905               "Menu Type %d not supported", src->type);
  906     return -1;
  907      }
  908    
  909    if (m == NULL)
  910      return -1;
  911    
  912    m->flags = src->flags;
  913    return 0;
  914 }
  915 
  916 
  917 /*
  918  *  SLsmg MenuBar interface
  919  */
  920 
  921 static void simulate_hline (unsigned int n)
  922 {
  923    while (n--)
  924      SLsmg_write_string ("-");
  925 }
  926 
  927 static void simulate_box (int r, int c, unsigned int dr, unsigned int dc)
  928 {
  929    int rr, rmax;
  930 
  931    if ((dr < 1) || (dc < 2)) return;
  932 
  933    dr--; 
  934    dc--;
  935    SLsmg_gotorc (r, c);
  936    SLsmg_write_string ("+");
  937    simulate_hline (dc-1);
  938    SLsmg_write_string ("+");
  939    SLsmg_gotorc (r + dr, c);
  940    SLsmg_write_string ("+");
  941    simulate_hline (dc-1);
  942    SLsmg_write_string ("+");
  943    
  944    rmax = r + dr;
  945    for (rr = r + 1; rr < rmax; rr++)
  946      {
  947     SLsmg_gotorc (rr, c);
  948     SLsmg_write_string ("|");
  949     SLsmg_gotorc (rr, c + dc);
  950     SLsmg_write_string ("|");
  951      }
  952 }
  953 
  954 /* I would prefer to use real up/down arrows but I cannot depend upon their
  955  * portability.
  956  */
  957 static void draw_up_arrow (int r, int c)
  958 {
  959    SLsmg_gotorc (r, c);
  960    SLsmg_write_string ("(-)");
  961 }
  962 
  963 static void draw_down_arrow (int r, int c)
  964 {
  965    SLsmg_gotorc (r, c);
  966    SLsmg_write_string ("(+)");
  967 }
  968 
  969 static void draw_name (char *name, int color0, int color1, unsigned int field_width)
  970 {
  971    unsigned char *s, *smax;
  972    unsigned int name_width;
  973 
  974    s = (unsigned char *) name;
  975    smax = s + strlen (name);
  976 #if SLANG_VERSION >= 20000
  977    name_width = SLsmg_strwidth (s, smax);
  978 #else
  979    name_width = smax - s;
  980 #endif
  981 
  982    while ((s < smax) && (*s != '&'))
  983      s++;
  984 
  985    SLsmg_set_color (color0);
  986    SLsmg_write_chars ((unsigned char *) name, s);
  987 
  988    if (s < smax)
  989      {
  990     unsigned char *s1;
  991     
  992     name_width--;
  993     s++;                   /* skip & */
  994     SLsmg_set_color (color1);
  995     s1 = jed_multibyte_chars_forward (s, smax, 1, NULL, 1);
  996     SLsmg_write_chars (s, s1);
  997     SLsmg_set_color (color0);
  998     s = s1;
  999 
 1000     if (s < smax)
 1001       SLsmg_write_chars (s, smax);
 1002      }
 1003 
 1004    if (name_width < field_width)
 1005      SLsmg_write_nstring ("", field_width - name_width);
 1006 }
 1007 
 1008       
 1009 static int draw_menu_bar (Menu_Bar_Type *b)
 1010 {
 1011    Menu_Node_Type **m;
 1012    unsigned int i, imax;
 1013    int active;
 1014 
 1015    SLsmg_gotorc (0, 0);
 1016 
 1017    SLsmg_set_color (JMENU_COLOR);
 1018    SLsmg_write_string (b->prefix_string);
 1019 
 1020    m = b->subnodes;
 1021    imax = b->num_subnodes;
 1022    active = -1;
 1023 
 1024    for (i = 0; i < imax; i++)
 1025      {
 1026     Menu_Popup_Type *p;
 1027     char *name;
 1028 
 1029     p = (Menu_Popup_Type *) m[i];
 1030     if (p->flags & MENU_ITEM_UNAVAILABLE)
 1031       continue;
 1032 
 1033     b->item_columns[i] = SLsmg_get_column ();
 1034 
 1035     if (p->type == MENU_NODE_SEPARATOR)
 1036       name = "          ";
 1037     else
 1038       name = p->name;
 1039 
 1040     if (p->flags & MENU_SELECTION)
 1041       {
 1042          if (p->type == MENU_NODE_POPUP)
 1043            active = i;
 1044 
 1045          draw_name (name, JMENU_SELECTION_COLOR, JMENU_SELECTED_CHAR_COLOR, 0);
 1046       }
 1047     else
 1048       draw_name (name, JMENU_COLOR, JMENU_CHAR_COLOR, 0);
 1049 
 1050     SLsmg_set_color (JMENU_COLOR);
 1051     SLsmg_write_string ("   ");
 1052      }
 1053 
 1054    SLsmg_set_color (JMENU_COLOR);
 1055    SLsmg_erase_eol ();
 1056    
 1057    return active;
 1058 }
 1059 
 1060 static int draw_keystring (Menu_Keystring_Fun_Type *k, int color0, int color1, unsigned int field_width)
 1061 {
 1062    int i;
 1063    SLang_Key_Type *key, *key_root;
 1064    FVOID_STAR fp;
 1065    unsigned char type;
 1066    char buf[3];
 1067    unsigned int best_len;
 1068    char *best_keystring;
 1069    SLang_Key_Type *best_key;
 1070    char *name;
 1071 
 1072    draw_name (k->name, color0, color1, field_width);
 1073 
 1074    name = k->keystring;
 1075    /* Now try to draw the binding */
 1076 
 1077    if (NULL == (fp = (FVOID_STAR) SLang_find_key_function(name, CBuf->keymap)))
 1078      type = SLKEY_F_INTERPRET;
 1079    else type = SLKEY_F_INTRINSIC;
 1080 
 1081    best_keystring = NULL;
 1082    best_len = 0xFFFF;
 1083    best_key = NULL;
 1084 
 1085    key_root = CBuf->keymap->keymap;
 1086 
 1087    for (i = 0; i < 256; i++, key_root++)
 1088      {
 1089 #ifdef IBMPC_SYSTEM
 1090     if ((i == 0) || (i == 0xE0))
 1091       continue;
 1092 #endif
 1093 
 1094     key = key_root->next;
 1095     if ((key == NULL) && (type == key_root->type))
 1096       {
 1097          if (type == SLKEY_F_INTERPRET)
 1098            {
 1099           if (strcmp (name, key_root->f.s))
 1100             continue;
 1101            }
 1102          else if ((type != SLKEY_F_INTRINSIC) || (fp != key_root->f.f))
 1103            continue;
 1104 
 1105          buf[0] = i;
 1106          buf[1] = 0;
 1107 #ifndef IBMPC_SYSTEM
 1108          if (i == 0)
 1109            {
 1110           buf[0] = '^';
 1111           buf[1] = '@';
 1112           buf[2] = 0;
 1113            }
 1114 #endif
 1115          best_keystring = buf;
 1116          break;
 1117       }
 1118 
 1119     while (key != NULL)
 1120       {
 1121          char *s;
 1122          SLang_Key_Type *this_key = key;
 1123          
 1124          key = key->next;
 1125 
 1126          if (this_key->type != type)
 1127            continue;
 1128 
 1129          if (type == SLKEY_F_INTERPRET)
 1130            {
 1131           if (strcmp (name, this_key->f.s))
 1132             continue;
 1133            }
 1134          else if ((type != SLKEY_F_INTRINSIC) || (fp != this_key->f.f))
 1135            continue;
 1136 
 1137          s = SLang_make_keystring (this_key->str);
 1138          if (s == NULL)
 1139            continue;
 1140 
 1141          if (strlen (s) < best_len)
 1142            {
 1143           best_key = this_key;
 1144           best_len = strlen (s);
 1145            }
 1146       }
 1147      }
 1148    
 1149    if (best_keystring == NULL)
 1150      {
 1151     if (best_key == NULL)
 1152       return 0;
 1153     
 1154     best_keystring = SLang_make_keystring (best_key->str);
 1155     if (best_keystring == NULL)
 1156       return 0;
 1157      }
 1158    
 1159    best_len = strlen (best_keystring);
 1160    if (best_len > 4)
 1161      return 0;
 1162 
 1163    SLsmg_forward (-4);
 1164    SLsmg_set_color (color0);
 1165    SLsmg_write_nchars (best_keystring, best_len);
 1166    return 0;
 1167 }
 1168 
 1169 static int draw_popup_menu (Menu_Popup_Type *p, int r, int c)
 1170 {
 1171    int active_row, active_col;
 1172    unsigned int dr, dc;
 1173    Menu_Node_Type **l, **lmax;
 1174    Menu_Popup_Type *p_active;
 1175 
 1176    Active_Popup = p;
 1177 
 1178    if (r == 0)
 1179      r = 1;
 1180    
 1181    dr = p->num_subnodes + 2;
 1182    dc = p->min_width + 5 + 4;          /* allow room for keystring */
 1183    
 1184    if (c + (int)dc >= Jed_Num_Screen_Cols)
 1185      {
 1186     if ((int)dc > Jed_Num_Screen_Cols)
 1187       c = 0;
 1188     else
 1189       c = Jed_Num_Screen_Cols - (int)dc;
 1190      }
 1191 
 1192    if (r + (int)dr >= Jed_Num_Screen_Rows)
 1193      {
 1194     if ((int)dr >= Jed_Num_Screen_Rows)
 1195       {
 1196          r = 1;
 1197          dr = Jed_Num_Screen_Rows - 1;
 1198       }
 1199     else
 1200       r = Jed_Num_Screen_Rows - (int)dr;
 1201      }
 1202 
 1203    SLsmg_set_color_in_region (JMENU_SHADOW_COLOR, r + 1, c + 1, dr, dc);
 1204    SLsmg_set_color (JMENU_POPUP_COLOR);
 1205    /* SLsmg_fill_region (r, c, dr, dc, ' '); */
 1206    if (Jed_Simulate_Graphic_Chars)
 1207      simulate_box (r, c, dr, dc);
 1208    else
 1209      SLsmg_draw_box (r, c, dr, dc);
 1210 
 1211    p->row = r;
 1212    p->column = c;
 1213    p->max_row = r + dr;
 1214    p->max_col = c + dc;
 1215 
 1216    /* Make sure a selection is present */
 1217    (void) get_selected_menu_item (p);
 1218 
 1219    l = p->subnodes;
 1220    lmax = l + p->num_subnodes;
 1221    
 1222    if (p->num_subnodes + 2 > dr)
 1223      {
 1224     unsigned int page;
 1225     unsigned int nr = dr - 2;
 1226     unsigned int col;
 1227     
 1228     col = c + dc - 4;
 1229     page = p->active_node / nr;
 1230     if (page)
 1231       {
 1232          l += page * nr;
 1233          draw_up_arrow (r, col);
 1234       }
 1235     if (lmax > l + nr)
 1236       {
 1237          lmax = l + nr;
 1238          draw_down_arrow (r + dr - 1, col);
 1239       }
 1240     else
 1241       l = lmax - nr;
 1242      }
 1243    
 1244    p->visible_node_offset = (int) (l - p->subnodes);
 1245 
 1246    c++;
 1247    r++;
 1248    p_active = NULL;
 1249    active_row = r;
 1250    active_col = c;
 1251 
 1252    dc -= 3;
 1253 
 1254    while (l < lmax)
 1255      {
 1256     Menu_Node_Type *m;
 1257     int color0, color1;
 1258 
 1259     m = *l;
 1260 
 1261     SLsmg_gotorc (r, c);
 1262 
 1263     color0 = JMENU_POPUP_COLOR;
 1264     color1 = JMENU_CHAR_COLOR;
 1265     
 1266     if (m->flags & MENU_SELECTION)
 1267       {
 1268          active_row = r;
 1269          active_col = c + dc;
 1270          color0 = JMENU_SELECTION_COLOR;
 1271          color1 = JMENU_SELECTED_CHAR_COLOR;
 1272       }
 1273 
 1274     if ((m->flags & MENU_ACTIVE)
 1275         && (m->type == MENU_NODE_POPUP))
 1276       {
 1277          p_active = (Menu_Popup_Type *)m;
 1278          p_active->row = active_row;
 1279          p_active->column = active_col - dc/2;
 1280       }
 1281 
 1282     SLsmg_set_color (color0);
 1283     switch (m->type)
 1284       {
 1285        case MENU_NODE_SEPARATOR:
 1286          SLsmg_write_nchars (" ", 1);
 1287          if (Jed_Simulate_Graphic_Chars)
 1288            simulate_hline (dc - 1);
 1289          else
 1290            SLsmg_draw_hline (dc-1);
 1291          SLsmg_write_nchars (" ", 1);
 1292          break;
 1293          
 1294        case MENU_NODE_POPUP:
 1295          SLsmg_write_nchars (" ", 1);
 1296          draw_name (m->name, color0, color1, dc);
 1297          SLsmg_gotorc (r, c + (dc - 2));
 1298          SLsmg_write_nchars (">>>", 3);
 1299          break;
 1300 
 1301        case MENU_NODE_KEYSTRING:
 1302          SLsmg_write_nchars (" ", 1);
 1303          draw_keystring ((Menu_Keystring_Fun_Type *)m, color0, color1, dc);
 1304          break;
 1305 
 1306        default:
 1307          SLsmg_write_nchars (" ", 1);
 1308          draw_name (m->name, color0, color1, dc);
 1309          break;
 1310       }
 1311     l++;
 1312     r++;
 1313      }
 1314    
 1315    if (p_active != NULL)
 1316      return draw_popup_menu (p_active, p_active->row, p_active->column);
 1317    
 1318    SLsmg_gotorc (active_row, active_col);
 1319    return 0;
 1320 }
 1321 
 1322 static Menu_Bar_Type *get_active_menubar (void)
 1323 {
 1324    Menu_Bar_Type *b;
 1325 
 1326    /* Active_Popup = NULL; */
 1327    b = Active_Menu_Bar;
 1328 
 1329    if (b == NULL)
 1330      {
 1331     Buffer *buf = CBuf;
 1332 
 1333     if (IN_MINI_WINDOW)
 1334       {
 1335          if (NULL == (buf = jed_get_mini_action_buffer ()))
 1336            return NULL;
 1337       }
 1338 
 1339     if (NULL == (b = buf->menubar))
 1340       b = Global_Menu_Bar;
 1341 
 1342     if (b == NULL)
 1343       return NULL;
 1344     
 1345      }
 1346    /* Active_Popup = (Menu_Popup_Type *) b; */
 1347    return b;
 1348 }
 1349 
 1350 int jed_redraw_menus (void)
 1351 {
 1352    Menu_Popup_Type *p;
 1353    Menu_Bar_Type *b;
 1354    int active;
 1355 
 1356 #if 0
 1357    if (NULL == (b = CBuf->menubar))
 1358      b = Global_Menu_Bar;
 1359 #else
 1360    b = get_active_menubar ();
 1361 #endif
 1362 
 1363    Active_Popup = (Menu_Popup_Type *) b;
 1364 
 1365    if (b == NULL)
 1366      {
 1367     SLsmg_gotorc (0, 0);
 1368     SLsmg_set_color (0);
 1369     SLsmg_erase_eol ();
 1370     return 0;
 1371      }
 1372    
 1373    active = draw_menu_bar (b);
 1374    if (active == -1)
 1375      return 0;
 1376 
 1377    touch_screen ();
 1378 
 1379    p = (Menu_Popup_Type *)b->subnodes[active];
 1380 
 1381    if (0 == (p->flags & MENU_ACTIVE))
 1382      {
 1383     SLsmg_gotorc (0, b->item_columns[active]);
 1384     return 1;
 1385      }
 1386 
 1387    draw_popup_menu (p, 0, b->item_columns[active]);
 1388    return 1;
 1389 }
 1390 
 1391 
 1392 /* Keyboard Interface */
 1393 
 1394 static int find_active_popup (void)
 1395 {
 1396    Menu_Popup_Type *p;
 1397 
 1398    if (Active_Menu_Bar == NULL)
 1399      return -1;
 1400    
 1401    p = (Menu_Popup_Type *) Active_Menu_Bar;
 1402    
 1403    while (1)
 1404      {
 1405     Active_Popup = p;
 1406     p = (Menu_Popup_Type *) get_selected_menu_item (p);
 1407 
 1408     if ((p == NULL) || (p->type != MENU_NODE_POPUP))
 1409       return 0;
 1410 
 1411     if (0 == (p->flags & MENU_ACTIVE))
 1412       return 0;
 1413 
 1414     if (0 == (p->flags & MENU_POPUP_PREPARED))
 1415       return select_menu_cmd ();
 1416      }
 1417 }
 1418     
 1419     
 1420 static int next_menubar_cmd (void)
 1421 {
 1422    unsigned int flags;
 1423    Menu_Popup_Type *p;
 1424    
 1425    if (NULL == (p = (Menu_Popup_Type *) Active_Menu_Bar))
 1426      return -1;
 1427 
 1428    flags = get_active_node_flags (p) & MENU_ACTIVE;
 1429    
 1430    /* (void) unselect_active_node ((Menu_Popup_Type *)Active_Menu_Bar); */
 1431    (void) select_next_active_node (p, p->active_node, flags);
 1432    (void) find_active_popup ();
 1433    return 1;
 1434 }
 1435 
 1436 static int prev_menubar_cmd (void)
 1437 {
 1438    unsigned int flags;
 1439    Menu_Popup_Type *p;
 1440    
 1441    if (NULL == (p = (Menu_Popup_Type *) Active_Menu_Bar))
 1442      return -1;
 1443 
 1444    flags = get_active_node_flags (p) & MENU_ACTIVE;
 1445    /* (void) unselect_active_node ((Menu_Popup_Type *)Active_Menu_Bar); */
 1446    (void) select_prev_active_node (p, p->active_node, flags);
 1447    (void) find_active_popup ();
 1448    return 1;
 1449 }
 1450 
 1451 int jed_exit_menu_bar (void)
 1452 {
 1453    while (Active_Popup != NULL)
 1454      {
 1455     unselect_active_node (Active_Popup);
 1456     Active_Popup->active_node = 0;
 1457     Active_Popup->flags &= ~MENU_POPUP_PREPARED;
 1458     Active_Popup = Active_Popup->parent;
 1459      }
 1460 
 1461    Active_Menu_Bar = NULL;
 1462    Jed_Menus_Active = 0;
 1463    return 1;
 1464 }
 1465 
 1466 static int down_menu_cmd (void)
 1467 {
 1468    if (Active_Popup == NULL)
 1469      return -1;
 1470    
 1471    /* unselect_active_node (Active_Popup); */
 1472    select_next_active_node (Active_Popup, Active_Popup->active_node, 0);
 1473    return 1;
 1474 }
 1475 
 1476 static int up_menu_cmd (void)
 1477 {
 1478    if (Active_Popup == NULL)
 1479      return -1;
 1480    
 1481    /* unselect_active_node (Active_Popup); */
 1482    select_prev_active_node (Active_Popup, Active_Popup->active_node, 0);
 1483    return 1;
 1484 }
 1485 
 1486 static int pgup_menu_cmd (void)
 1487 {
 1488    if (Active_Popup == NULL)
 1489      return -1;
 1490 
 1491    select_next_active_node (Active_Popup, Active_Popup->num_subnodes, 0);
 1492    return 1;
 1493 }
 1494 
 1495 static int pgdn_menu_cmd (void)
 1496 {
 1497    if (Active_Popup == NULL)
 1498      return -1;
 1499 
 1500    select_prev_active_node (Active_Popup, 0, 0);
 1501    return 1;
 1502 }
 1503 
 1504 static int execute_keystring (char *s)
 1505 {
 1506    int (*f)(void);
 1507 
 1508    if (NULL != (f = (int (*)(void)) (SLang_find_key_function(s, CBuf->keymap))))
 1509      return (*f) ();
 1510    
 1511    if ((*s == '.')
 1512        || !SLang_execute_function(s))
 1513      SLang_load_string(s);
 1514 
 1515    return 1;
 1516 }
 1517 
 1518 static char *get_full_popup_name (Menu_Popup_Type *p)
 1519 {
 1520    Menu_Popup_Type *parent;
 1521    unsigned int len;
 1522    char *name;
 1523    char *s;
 1524 
 1525    len = strlen (p->name);
 1526    parent = p->parent;
 1527    while (parent != NULL)
 1528      {
 1529     len += 1 + strlen (parent->name);
 1530     parent = parent->parent;
 1531      }
 1532    
 1533    name = SLmalloc (len + 1);
 1534    if (name == NULL)
 1535      return NULL;
 1536    
 1537    s = (name + len) - strlen (p->name);
 1538    strcpy (s, p->name);
 1539    parent = p->parent;
 1540    while (parent != NULL)
 1541      {
 1542     s--;
 1543     *s = '.';
 1544     len = strlen (parent->name);
 1545     s -= len;
 1546     strncpy (s, parent->name, len);
 1547     parent = parent->parent;
 1548      }
 1549    
 1550    return name;
 1551 }
 1552 
 1553 static int run_popup_callback (Menu_Popup_Type *p, SLang_Name_Type *cb)
 1554 {
 1555    char *name;
 1556 
 1557    if (NULL == (name = get_full_popup_name (p)))
 1558      return -1;
 1559 
 1560    if (-1 == SLang_push_string (name))
 1561      {
 1562     SLfree (name);
 1563     return -1;
 1564      }
 1565    SLfree (name);
 1566 
 1567    if (0 != SLexecute_function (cb))
 1568      return -1;
 1569 
 1570    return 0;
 1571 }
 1572 
 1573    
 1574 static int prepare_popup (Menu_Popup_Type *p)
 1575 {
 1576    SLang_Name_Type *cb;
 1577 
 1578    if (NULL != (cb = p->select_popup_callback))
 1579      {
 1580     free_menu_popup_subnodes (p);
 1581     if (-1 == run_popup_callback (p, cb))
 1582       return -1;
 1583      }
 1584    
 1585    if (NULL != (cb = p->tweak_popup_callback))
 1586      {
 1587     if (-1 == run_popup_callback (p, cb))
 1588       return -1;
 1589      }
 1590    
 1591    p->flags |= MENU_POPUP_PREPARED;
 1592    return 0;
 1593 }
 1594 
 1595 
 1596 static int select_menu_cmd (void)
 1597 {
 1598    Menu_Node_Type *m;
 1599    Menu_Popup_Type *p;
 1600    Menu_C_Fun_Type *c;
 1601    SLang_Name_Type *nt;
 1602    char *str;
 1603 
 1604    m = get_selected_menu_item (Active_Popup);
 1605    if (m == NULL)
 1606      return -1;
 1607 
 1608    switch (m->type)
 1609      {
 1610       case MENU_NODE_POPUP:
 1611 #if 0
 1612     m->flags |= MENU_ACTIVE;
 1613     p = (Menu_Popup_Type *) m;
 1614 #else
 1615     /* Do it this way to avoid DEC C ansi-aliasing warning. */
 1616     p = (Menu_Popup_Type *) m;
 1617     p->flags |= MENU_ACTIVE;
 1618 #endif
 1619     if (-1 == prepare_popup (p))
 1620       return -1;
 1621     Active_Popup = p;
 1622     select_next_active_node (p, p->num_subnodes, 0);
 1623     return 1;
 1624 
 1625       case MENU_NODE_FUN_SLANG:
 1626     nt = ((Menu_SLang_Fun_Type *) m)->slang_fun;
 1627     jed_exit_menu_bar ();
 1628     if (nt == NULL)
 1629       return -1;
 1630     if ((-1 == SLang_start_arg_list ())
 1631         || (-1 == SLang_push_anytype (((Menu_SLang_Fun_Type*)m)->client_data))
 1632         || (-1 == SLang_end_arg_list ()))
 1633       return -1;
 1634 
 1635     return SLexecute_function (nt);
 1636 
 1637       case MENU_NODE_KEYSTRING:
 1638     str = ((Menu_Keystring_Fun_Type *) m)->keystring;
 1639     /* Grab a copy while it is still available */
 1640     if (NULL == SLang_create_slstring (str))
 1641       return -1;
 1642     jed_exit_menu_bar ();
 1643     (void) execute_keystring (str);
 1644     SLang_free_slstring (str);
 1645     break;
 1646 
 1647       case MENU_NODE_FUN_C:
 1648     c = (Menu_C_Fun_Type *) m;
 1649     jed_exit_menu_bar ();
 1650     if (c->c_fun != NULL)
 1651       return -1;
 1652     return c->c_fun ();
 1653     
 1654      }
 1655    return 0;
 1656 }
 1657 
 1658 static int back_menu_cmd (void)
 1659 {
 1660    if ((Active_Popup == NULL)
 1661        || (Active_Popup == (Menu_Popup_Type *)Active_Menu_Bar)
 1662        || (Active_Popup->parent == (Menu_Popup_Type *) Active_Menu_Bar))
 1663      return jed_exit_menu_bar ();
 1664 
 1665    Active_Popup->flags &= ~(MENU_ACTIVE|MENU_POPUP_PREPARED);
 1666    Active_Popup = Active_Popup->parent;
 1667    return 1;
 1668 }
 1669 
 1670 static Menu_Node_Type *find_subnode_via_char (Menu_Popup_Type *p, char ch)
 1671 {
 1672    Menu_Node_Type **l, **lmax;
 1673    unsigned int two;
 1674 
 1675    if (p == NULL)
 1676      return NULL;
 1677    
 1678    two = 2;
 1679 
 1680    while (two)
 1681      {
 1682     l = p->subnodes;
 1683     lmax = l + p->num_subnodes;
 1684    
 1685     while (l < lmax)
 1686       {
 1687          Menu_Node_Type *m;
 1688          char *s;
 1689          
 1690          m = *l++;
 1691          
 1692          if (m->type == MENU_NODE_SEPARATOR)
 1693            continue;
 1694          
 1695          if (m->flags & MENU_ITEM_UNAVAILABLE)
 1696            continue;
 1697 
 1698          s = strchr (m->name, '&');
 1699          if (s == NULL)
 1700            continue;
 1701     
 1702          if (s[1] == ch)
 1703            return m;
 1704       }
 1705     
 1706     ch = (char) CHANGE_CASE(ch);
 1707     two--;
 1708      }
 1709    
 1710    return NULL;
 1711 }
 1712 
 1713 static int select_via_char_cmd (void)
 1714 {
 1715    Menu_Node_Type *m;
 1716    
 1717    m = find_subnode_via_char (Active_Popup, (char) SLang_Last_Key_Char);
 1718    if (m == NULL)
 1719      return -1;
 1720 
 1721    set_node_selection (Active_Popup, m);
 1722    return select_menu_cmd ();
 1723 }
 1724 
 1725    
 1726 static SLKeyMap_List_Type *Menu_Keymap;
 1727 
 1728 static SLKeymap_Function_Type Menu_Keymap_Functions [] =
 1729 {
 1730      {"next_menubar_menu", next_menubar_cmd},
 1731      {"prev_menubar_menu", prev_menubar_cmd},
 1732      {"exit_menubar",   jed_exit_menu_bar},
 1733      {"next_menu_item", down_menu_cmd},
 1734      {"prev_menu_item", up_menu_cmd},
 1735      {"top_menu_item",  pgup_menu_cmd},
 1736      {"bot_menu_item",  pgdn_menu_cmd},
 1737      {"select_menu_item", select_menu_cmd},
 1738      {"back_menu",  back_menu_cmd},
 1739 
 1740      {NULL, NULL}
 1741 };
 1742 
 1743 #ifndef IBMPC_SYSTEM
 1744 # ifdef HAS_MOUSE
 1745 static int xterm_mouse_cmd (void);
 1746 # endif
 1747 #endif
 1748 
 1749 static int init_menu_keymap (void)
 1750 {
 1751    int ch;
 1752    char simple[3];
 1753 
 1754    if (NULL == (Menu_Keymap = SLang_create_keymap ("menu", NULL)))
 1755      return -1;
 1756 
 1757    Menu_Keymap->functions = Menu_Keymap_Functions;
 1758    
 1759    simple[1] = 0;
 1760    for (ch = 0; ch < 256; ch++)
 1761      {
 1762     simple[0] = (char) ch;
 1763     SLkm_define_key (simple, (FVOID_STAR) select_via_char_cmd, Menu_Keymap);
 1764      }
 1765    simple [0] = 27;
 1766    simple [2] = 0;
 1767    for (ch = 'a'; ch <= 'z'; ch++)
 1768      {
 1769     simple [1] = (char) ch;
 1770     SLkm_define_key (simple, (FVOID_STAR) select_via_char_cmd, Menu_Keymap);
 1771      }
 1772 
 1773    
 1774    SLkm_define_key (" ", (FVOID_STAR) back_menu_cmd, Menu_Keymap);
 1775    SLkm_define_key ("^?", (FVOID_STAR) back_menu_cmd, Menu_Keymap);
 1776    SLkm_define_key ("^H", (FVOID_STAR) back_menu_cmd, Menu_Keymap);
 1777    SLkm_define_key ("^G", (FVOID_STAR) jed_exit_menu_bar, Menu_Keymap);
 1778    SLkm_define_key ("^Z", (FVOID_STAR) sys_spawn_cmd, Menu_Keymap);
 1779    SLkm_define_key ("^M", (FVOID_STAR) select_menu_cmd, Menu_Keymap);
 1780 
 1781 #ifndef IBMPC_SYSTEM
 1782    SLkm_define_key ("\033[A", (FVOID_STAR) up_menu_cmd, Menu_Keymap);
 1783    SLkm_define_key ("\033OA", (FVOID_STAR) up_menu_cmd, Menu_Keymap);
 1784    SLkm_define_key ("\033[B", (FVOID_STAR) down_menu_cmd, Menu_Keymap);
 1785    SLkm_define_key ("\033OB", (FVOID_STAR) down_menu_cmd, Menu_Keymap);
 1786    SLkm_define_key ("\033[C", (FVOID_STAR) next_menubar_cmd, Menu_Keymap);
 1787    SLkm_define_key ("\033OC", (FVOID_STAR) next_menubar_cmd, Menu_Keymap);
 1788    SLkm_define_key ("\033[D", (FVOID_STAR) prev_menubar_cmd, Menu_Keymap);
 1789    SLkm_define_key ("\033OD", (FVOID_STAR) prev_menubar_cmd, Menu_Keymap);
 1790    SLkm_define_key ("\033[5~", (FVOID_STAR) pgup_menu_cmd, Menu_Keymap);
 1791    SLkm_define_key ("\033[6~", (FVOID_STAR) pgdn_menu_cmd, Menu_Keymap);
 1792 # ifdef __unix__
 1793    SLkm_define_key ("^(ku)", (FVOID_STAR) up_menu_cmd, Menu_Keymap);
 1794    SLkm_define_key ("^(kd)", (FVOID_STAR) down_menu_cmd, Menu_Keymap);
 1795    SLkm_define_key ("^(kr)", (FVOID_STAR) next_menubar_cmd, Menu_Keymap);
 1796    SLkm_define_key ("^(kl)", (FVOID_STAR) prev_menubar_cmd, Menu_Keymap);
 1797    SLkm_define_key ("^(kP)", (FVOID_STAR) pgup_menu_cmd, Menu_Keymap);
 1798    SLkm_define_key ("^(kN)", (FVOID_STAR) pgdn_menu_cmd, Menu_Keymap);
 1799 # endif
 1800 # ifdef HAS_MOUSE
 1801    SLkm_define_key ("\033[M", (FVOID_STAR) xterm_mouse_cmd, Menu_Keymap);
 1802 # endif
 1803 #else                      /* IBMPC_SYSTEM */
 1804 #include "doskeys.h"
 1805    
 1806    SLkm_define_key (PC_UP, (FVOID_STAR) up_menu_cmd, Menu_Keymap);
 1807    SLkm_define_key (PC_UP1, (FVOID_STAR) up_menu_cmd, Menu_Keymap);
 1808    SLkm_define_key (PC_DN, (FVOID_STAR) down_menu_cmd, Menu_Keymap);
 1809    SLkm_define_key (PC_DN1, (FVOID_STAR) down_menu_cmd, Menu_Keymap);
 1810    SLkm_define_key (PC_RT, (FVOID_STAR) next_menubar_cmd, Menu_Keymap);
 1811    SLkm_define_key (PC_RT1, (FVOID_STAR) next_menubar_cmd, Menu_Keymap);
 1812    SLkm_define_key (PC_LT, (FVOID_STAR) prev_menubar_cmd, Menu_Keymap);
 1813    SLkm_define_key (PC_LT1, (FVOID_STAR) prev_menubar_cmd, Menu_Keymap);
 1814    SLkm_define_key (PC_PGUP, (FVOID_STAR) pgup_menu_cmd, Menu_Keymap);
 1815    SLkm_define_key (PC_PGUP1, (FVOID_STAR) pgup_menu_cmd, Menu_Keymap);
 1816    SLkm_define_key (PC_PGDN, (FVOID_STAR) pgdn_menu_cmd, Menu_Keymap);
 1817    SLkm_define_key (PC_PGDN1, (FVOID_STAR) pgdn_menu_cmd, Menu_Keymap);
 1818 #endif
 1819 
 1820 #ifdef HAS_MOUSE
 1821    SLkm_define_key ("\033^@", (FVOID_STAR) jed_mouse_cmd, Menu_Keymap);
 1822 #endif
 1823    return 0;
 1824 }
 1825 
 1826 
 1827 SLang_Key_Type *jed_menu_do_key (void)
 1828 {
 1829    int ch;
 1830 
 1831    if (Executing_Keyboard_Macro
 1832        || (Read_This_Character != NULL))
 1833      return SLang_do_key (Menu_Keymap, jed_getkey);
 1834 
 1835    ch = my_getkey ();
 1836 
 1837    if (SLKeyBoard_Quit || SLang_get_error ())
 1838      {
 1839     jed_exit_menu_bar ();
 1840     return NULL;
 1841      }
 1842 
 1843    if (ch == 27)               /* ESC */
 1844      {
 1845     int tsecs = 2;
 1846     if (0 == input_pending (&tsecs))
 1847       ch = 127;
 1848      }
 1849    ungetkey (&ch);
 1850    
 1851    return SLang_do_key (Menu_Keymap, jed_getkey);
 1852 }
 1853 
 1854 static int exec_menubar_callback (Menu_Bar_Type *b, SLang_Name_Type **ntp)
 1855 {
 1856    SLang_Name_Type *nt;
 1857    
 1858    nt = *ntp;
 1859    if (nt == NULL)
 1860      return 0;
 1861 
 1862    if (SLang_get_error ())
 1863      return -1;
 1864 
 1865    if (-1 == SLang_push_string (b->name))
 1866      return -1;
 1867    
 1868    if (-1 == SLexecute_function (nt))
 1869      {
 1870     if (Active_Menu_Bar == b)      /* disable callback */
 1871       {
 1872 #if SLANG_VERSION > 10400
 1873          SLang_free_function (nt);
 1874 #endif
 1875          *ntp = NULL;
 1876       }
 1877     return -1;
 1878      }
 1879 
 1880    return 0;
 1881 }
 1882 
 1883 
 1884 void jed_notify_menu_buffer_changed (void)
 1885 {
 1886    Menu_Bar_Type *b;
 1887    int err;
 1888 
 1889    if (NULL == (b = get_active_menubar ()))
 1890      return;
 1891 
 1892    err = SLang_get_error ();
 1893    SLang_set_error (0);
 1894    (void) exec_menubar_callback (b, &b->init_callback);
 1895    if (SLang_get_error () == 0)
 1896      SLang_set_error (err);
 1897 }
 1898 
 1899 
 1900 int jed_select_menu_bar (void)
 1901 {
 1902    Menu_Popup_Type *p;
 1903    Menu_Node_Type **l, **lmax;
 1904 
 1905    if (IN_MINI_WINDOW)
 1906      {
 1907     /* For now do not allow access to menus from the minibuffer
 1908      * since the minibuffer is not recursive
 1909      */
 1910     return -1;
 1911      }
 1912    
 1913    if (NULL == (Active_Menu_Bar = get_active_menubar ()))
 1914      return -1;
 1915    
 1916    p = (Menu_Popup_Type *) Active_Menu_Bar;
 1917    Active_Popup = p;
 1918 
 1919    l = p->subnodes;
 1920    lmax = l + p->num_subnodes;
 1921 
 1922    /* Reset each sub-node to its default value.  This is necessary 
 1923     * to ensure that keyboard macros will work when one switches from
 1924     * one node to another via next/prev_menubar_cmd functions.
 1925     */
 1926    while (l < lmax)
 1927      {
 1928     Menu_Popup_Type *pp = (Menu_Popup_Type *) *l++;
 1929 
 1930     if (pp->type == MENU_NODE_POPUP)
 1931       {
 1932          (void) unselect_active_node (pp);
 1933          pp->active_node = 0;
 1934       }
 1935      }
 1936 
 1937    p->active_node = 0;
 1938    
 1939    if (-1 == exec_menubar_callback (Active_Menu_Bar, &Active_Menu_Bar->select_callback))
 1940      {
 1941     jed_exit_menu_bar ();
 1942     return -1;
 1943      }
 1944    
 1945    (void) get_selected_menu_item (p);
 1946    touch_screen ();
 1947    Jed_Menus_Active = 1;
 1948    return 0;
 1949 }
 1950 
 1951 /* Interpreter interface */
 1952 
 1953 static Menu_Node_Type *find_menu_node1 (Menu_Popup_Type *m, 
 1954                     char *name,
 1955                     int stop_at_last_popup)
 1956 {
 1957    char *name_end;
 1958    Menu_Node_Type **l, **lmax;
 1959 
 1960    name_end = strchr (name, '.');
 1961    if (name_end == NULL)
 1962      name_end = name + strlen (name);
 1963 
 1964    l = m->subnodes;
 1965    lmax = l + m->num_subnodes;
 1966    
 1967    while (l < lmax)
 1968      {
 1969     Menu_Popup_Type *p;
 1970     
 1971     p = (Menu_Popup_Type *) *l++;
 1972 
 1973     if (0 == menu_name_eqs (p->name, name, name_end))
 1974       continue;
 1975 
 1976     if (*name_end == 0)
 1977       {
 1978          if (stop_at_last_popup
 1979          && ((p->type != MENU_NODE_POPUP) 
 1980              || (p->type != MENU_NODE_MENUBAR)))
 1981            return (Menu_Node_Type *)m;
 1982 
 1983          return (Menu_Node_Type *)p;
 1984       }
 1985          
 1986     if (p->type == MENU_NODE_POPUP)
 1987       return find_menu_node1 (p, name_end + 1, stop_at_last_popup);
 1988 
 1989     return NULL;
 1990      }
 1991 
 1992    return NULL;
 1993 }
 1994 
 1995    
 1996 
 1997 static Menu_Node_Type *find_menu_node (char *name, int stop_at_last_popup)
 1998 {
 1999    char *s;
 2000    Menu_Node_Type *m;
 2001 
 2002    m = (Menu_Node_Type *) menu_find_menu_bar (name, 1);
 2003    if (m == NULL)
 2004      return m;
 2005 
 2006    s = strchr (name, '.');
 2007    if (s == NULL)
 2008      return m;
 2009 
 2010    m = find_menu_node1 ((Menu_Popup_Type *)m, s + 1, stop_at_last_popup);
 2011 
 2012    if (m == NULL)
 2013      SLang_verror (SL_INTRINSIC_ERROR,
 2014            "Unable to find menu node %s",
 2015            name);
 2016    return m;
 2017 }
 2018 
 2019 static Menu_Popup_Type *find_menu_popup (char *name)
 2020 {
 2021    Menu_Popup_Type *m;
 2022    
 2023    m = (Menu_Popup_Type *) find_menu_node (name, 0);
 2024    if (m == NULL)
 2025      return m;
 2026 
 2027    if ((m->type != MENU_NODE_POPUP)
 2028        && (m->type != MENU_NODE_MENUBAR))
 2029      {
 2030     SLang_verror (SL_INVALID_PARM, 
 2031               "%s is not a menu node", name);
 2032     return NULL;
 2033      }
 2034 
 2035    return m;
 2036 }
 2037 
 2038 /* If name is NULL or non-existent, then insert at end */
 2039 static unsigned int find_where_to_insert (Menu_Popup_Type *p, char *name)
 2040 {
 2041    unsigned int i, num;
 2042 
 2043    num = p->num_subnodes;
 2044 
 2045    if (name != NULL) for (i = 0; i < num; i++)
 2046      {
 2047     if (0 == strcmp (name, p->subnodes[i]->name))
 2048       return i;
 2049      }
 2050    return num;
 2051 }
 2052 
 2053 static void create_menu_bar_cmd (char *name)
 2054 {
 2055    if (0 == strcmp ("Global", name))
 2056      {
 2057     Menu_Bar_Type *g = create_menu_bar (name, 5);
 2058     if (g != NULL)
 2059       jed_delete_menu_bar (Global_Menu_Bar);
 2060     Global_Menu_Bar = g;
 2061     return;
 2062      }
 2063 
 2064    if (NULL != menu_find_menu_bar (name, 0))
 2065      return;
 2066 
 2067    (void) create_menu_bar (name, 5);
 2068 }
 2069 
 2070 static void set_buffer_menu_bar_cmd (char *name)
 2071 {
 2072    Menu_Bar_Type *b;
 2073 
 2074    b = menu_find_menu_bar (name, 1);
 2075    if (b == NULL)
 2076      return;
 2077    
 2078    jed_delete_menu_bar (CBuf->menubar);
 2079    
 2080    CBuf->menubar = b;
 2081    b->num_refs += 1;
 2082 }
 2083 
 2084 static int pop_where_to_insert (Menu_Popup_Type *p, unsigned int *where)
 2085 {
 2086    if (SLang_peek_at_stack () == SLANG_STRING_TYPE)
 2087      {
 2088     char *s;
 2089     
 2090     if (-1 == SLang_pop_slstring (&s))
 2091       return -1;
 2092     *where = find_where_to_insert (p, s);
 2093     SLang_free_slstring (s);
 2094     return 0;
 2095      }
 2096    
 2097    if (-1 == SLang_pop_uinteger (where))
 2098      return -1;
 2099    
 2100    return 0;
 2101 }
 2102 
 2103 static void insert_popup_menu_cmd (char *dest, char *menu)
 2104 {
 2105    Menu_Popup_Type *m;
 2106    unsigned int where;
 2107 
 2108    m = find_menu_popup (dest);
 2109 
 2110    if (m == NULL)
 2111      return;
 2112 
 2113    if (-1 == pop_where_to_insert (m, &where))
 2114      return;
 2115 
 2116    insert_popup_menu (m, menu, where);
 2117 }
 2118 
 2119    
 2120 static void append_popup_menu_cmd (char *dest, char *menu)
 2121 {
 2122    Menu_Popup_Type *m;
 2123 
 2124    m = find_menu_popup (dest);
 2125 
 2126    if (m == NULL)
 2127      return;
 2128 
 2129    insert_popup_menu (m, menu, m->num_subnodes);
 2130 }
 2131 
 2132 static void insert_separator_cmd (char *name)
 2133 {
 2134    Menu_Popup_Type *m;
 2135    unsigned int where;
 2136 
 2137    m = find_menu_popup (name);
 2138 
 2139    if (m == NULL)
 2140      return;
 2141 
 2142    if (-1 == pop_where_to_insert (m, &where))
 2143      return;
 2144 
 2145    insert_separator (m, where);
 2146 }
 2147 
 2148 static void append_separator_cmd (char *name)
 2149 {
 2150    Menu_Popup_Type *m;
 2151 
 2152    m = find_menu_popup (name);
 2153 
 2154    if (m != NULL)
 2155      insert_separator (m, m->num_subnodes);
 2156 }
 2157 
 2158 static void insert_menu_item_cmd_internal (int is_fun, int do_append)
 2159 {
 2160    Menu_Popup_Type *m;
 2161    SLang_Name_Type *nt = NULL;
 2162    SLang_Any_Type *client_data = NULL;
 2163    char *str = NULL;
 2164    char *menu = NULL;
 2165    char *name = NULL;
 2166    unsigned int where;
 2167 
 2168    if (is_fun)
 2169      {
 2170     if (-1 == SLang_pop_anytype (&client_data))
 2171       return;
 2172 
 2173     if (NULL == (nt = SLang_pop_function ()))
 2174       goto free_and_return;
 2175      }
 2176    else if (-1 == SLang_pop_slstring (&str))
 2177      return;
 2178 
 2179    if (-1 == SLang_pop_slstring (&name))
 2180      goto free_and_return;
 2181 
 2182    if (-1 == SLang_pop_slstring (&menu))
 2183      goto free_and_return;
 2184    
 2185    if (NULL == (m = find_menu_popup (menu)))
 2186      goto free_and_return;
 2187    
 2188    if (do_append)
 2189      where = m->num_subnodes;
 2190    else if (-1 == pop_where_to_insert (m, &where))
 2191      goto free_and_return;
 2192 
 2193    if (nt != NULL)
 2194      {
 2195     if (NULL != insert_slang_fun_item (m, name, nt, client_data, where))
 2196       {
 2197          client_data = NULL;
 2198          nt = NULL;
 2199       }
 2200      }
 2201    else
 2202      (void) insert_keystring_item (m, name, str, where);
 2203    /* drop */
 2204 
 2205    free_and_return:
 2206 
 2207    if (client_data != NULL) 
 2208      SLang_free_anytype (client_data);
 2209    SLang_free_slstring (str);
 2210    SLang_free_slstring (menu);
 2211    SLang_free_slstring (name);
 2212 #if SLANG_VERSION > 10400
 2213    SLang_free_function (nt);
 2214 #endif
 2215 }
 2216 
 2217 static void insert_menu_item_cmd (void)
 2218 {
 2219    insert_menu_item_cmd_internal ((SLang_Num_Function_Args == 5), 0);
 2220 }
 2221 
 2222 static void append_menu_item_cmd (void)
 2223 {
 2224    insert_menu_item_cmd_internal ((SLang_Num_Function_Args == 4), 1);
 2225 }
 2226 
 2227 static void menu_delete_item_cmd (char *menu)
 2228 {
 2229    Menu_Popup_Type *parent;
 2230    Menu_Node_Type *child;
 2231 
 2232    parent = (Menu_Popup_Type *)find_menu_node (menu, 1);
 2233    child = find_menu_node (menu, 0);
 2234    if ((parent == NULL) || (child == NULL))
 2235      {
 2236     SLang_verror (SL_INVALID_PARM, 
 2237               "Menu %s does not exist", menu);
 2238     return;
 2239      }
 2240    menu_delete_node (parent, child);
 2241 }
 2242 
 2243 static void menu_delete_items_cmd (char *menu)
 2244 {
 2245    Menu_Popup_Type *p;
 2246 
 2247    if (NULL == (p = find_menu_popup (menu)))
 2248      return;
 2249 
 2250    menu_delete_nodes (p);
 2251 }
 2252 
 2253 static void set_object_available_cmd (char *name, int *flag)
 2254 {
 2255    Menu_Node_Type *m;
 2256    
 2257    if (NULL == (m = find_menu_node (name, 0)))
 2258      return;
 2259    
 2260    if (*flag) m->flags &= ~MENU_ITEM_UNAVAILABLE;
 2261    else
 2262      m->flags |= MENU_ITEM_UNAVAILABLE;
 2263 }
 2264 
 2265 static int pop_popup_callback (Menu_Popup_Type **pp, int type,
 2266                    SLang_Name_Type **ntp)
 2267 {
 2268    SLang_Name_Type *nt;
 2269    char *popup;
 2270    Menu_Popup_Type *p;
 2271 
 2272    if (SLang_peek_at_stack () == SLANG_NULL_TYPE)
 2273      {
 2274     (void) SLang_pop_null ();
 2275     nt = NULL;
 2276      }
 2277    else if (NULL == (nt = SLang_pop_function ()))
 2278      return -1;
 2279 
 2280    if (-1 == SLang_pop_slstring (&popup))
 2281      {
 2282 #if SLANG_VERSION > 10400
 2283     SLang_free_function (nt);
 2284 #endif
 2285     return -1;
 2286      }
 2287 
 2288    p = find_menu_popup (popup);
 2289    if (p == NULL)
 2290      {
 2291 #if SLANG_VERSION > 10400
 2292     SLang_free_function (nt);
 2293 #endif
 2294     SLang_free_slstring (popup);
 2295     return -1;
 2296      }
 2297    
 2298    if (type && (p->type != type))
 2299      {
 2300     SLang_verror (SL_INVALID_PARM, "%s does not specify the proper menu type", popup);
 2301 #if SLANG_VERSION > 10400
 2302     SLang_free_function (nt);
 2303 #endif
 2304     SLang_free_slstring (popup);
 2305     return -1;
 2306      }
 2307    
 2308    SLang_free_slstring (popup);
 2309 
 2310    *ntp = nt;
 2311    *pp = p;
 2312    return 0;
 2313 }
 2314 
 2315 static int pop_menubar_callback (Menu_Bar_Type **bp, SLang_Name_Type **nt)
 2316 {
 2317    return pop_popup_callback ((Menu_Popup_Type **)bp, MENU_NODE_MENUBAR, nt);
 2318 }
 2319 
 2320 static void set_select_menubar_callback (void)
 2321 {
 2322    Menu_Bar_Type *b;
 2323    SLang_Name_Type *nt;
 2324 
 2325    if (-1 == pop_menubar_callback (&b, &nt))
 2326      return;
 2327 
 2328    b->select_callback = nt;
 2329 }
 2330 
 2331 static void set_init_menubar_callback (void)
 2332 {
 2333    Menu_Bar_Type *b;
 2334    SLang_Name_Type *nt;
 2335    
 2336    if (-1 == pop_menubar_callback (&b, &nt))
 2337      return;
 2338 
 2339    b->init_callback = nt;
 2340 }
 2341 
 2342 
 2343 static void set_select_popup_callback (void)
 2344 {
 2345    Menu_Popup_Type *p;
 2346    SLang_Name_Type *nt;
 2347 
 2348    if (-1 == pop_popup_callback (&p, MENU_NODE_POPUP, &nt))
 2349      return;
 2350 
 2351    p->select_popup_callback = nt;
 2352 }
 2353 
 2354 static void set_tweak_popup_callback (void)
 2355 {
 2356    Menu_Popup_Type *p;
 2357    SLang_Name_Type *nt;
 2358 
 2359    if (-1 == pop_popup_callback (&p, MENU_NODE_POPUP, &nt))
 2360      return;
 2361 
 2362    p->tweak_popup_callback = nt;
 2363 }
 2364 
 2365 static void copy_menu_cmd (char *destname, char *srcname)
 2366 {
 2367    Menu_Popup_Type *dest;
 2368    Menu_Node_Type *src;
 2369 
 2370    dest = find_menu_popup (destname);
 2371    if (dest == NULL)
 2372      return;
 2373    
 2374    src = find_menu_node (srcname, 0);
 2375    if (src == NULL)
 2376      return;
 2377    
 2378    (void) copy_menu (dest, src);
 2379 }
 2380 
 2381 static void set_menu_bar_prefix_string (char *menubar, char *s)
 2382 {
 2383    Menu_Bar_Type *b;
 2384    
 2385    if (NULL == (b = menu_find_menu_bar (menubar, 1)))
 2386      return;
 2387 
 2388    s = SLang_create_slstring (s);
 2389    if (s == NULL)
 2390      return;
 2391    
 2392    SLang_free_slstring (b->prefix_string);
 2393    b->prefix_string = s;
 2394 }
 2395 
 2396    
 2397 static void popup_menu_cmd (char *menu)
 2398 {
 2399    char *popup;
 2400 
 2401    (void) jed_exit_menu_bar ();
 2402    if (-1 == jed_select_menu_bar ())
 2403      return;
 2404 
 2405    if (NULL == (menu = SLmake_string (menu)))
 2406      return;
 2407 
 2408    /* for now ignore the menubar name and use default */
 2409    popup = strchr (menu, '.');
 2410    if (popup != NULL)
 2411      popup++;
 2412 
 2413    while ((popup != NULL) && (Active_Popup != NULL))
 2414      {
 2415     Menu_Node_Type *m;
 2416     char *next_popup;
 2417     
 2418     next_popup = strchr (popup, '.');
 2419     if (next_popup != NULL)
 2420       *next_popup++ = 0;
 2421 
 2422     if (NULL == (m = find_subnode (Active_Popup, popup)))
 2423       {
 2424          SLang_verror (SL_INVALID_PARM, 
 2425                "Unable to find a popup menu called %s", menu);
 2426          break;
 2427       }
 2428     set_node_selection (Active_Popup, m);
 2429     if (-1 == select_menu_cmd ())
 2430       break;
 2431     
 2432     popup = next_popup;
 2433      }
 2434    
 2435    SLfree (menu);
 2436 }
 2437 
 2438 
 2439 static SLang_Intrin_Fun_Type Menu_Table[] =
 2440 {
 2441    MAKE_INTRINSIC_S("menu_create_menu_bar", create_menu_bar_cmd, VOID_TYPE),
 2442    MAKE_INTRINSIC_SS("menu_append_popup", append_popup_menu_cmd, VOID_TYPE),
 2443    MAKE_INTRINSIC_SS("menu_insert_popup", insert_popup_menu_cmd, VOID_TYPE),
 2444    MAKE_INTRINSIC_S("menu_use_menu_bar", set_buffer_menu_bar_cmd, VOID_TYPE),
 2445    MAKE_INTRINSIC_S("menu_append_separator", append_separator_cmd, VOID_TYPE),
 2446    MAKE_INTRINSIC_S("menu_insert_separator", insert_separator_cmd, VOID_TYPE),
 2447    MAKE_INTRINSIC_0("menu_append_item", append_menu_item_cmd, VOID_TYPE),
 2448    MAKE_INTRINSIC_0("menu_insert_item", insert_menu_item_cmd, VOID_TYPE),
 2449    MAKE_INTRINSIC_S("menu_delete_item", menu_delete_item_cmd, VOID_TYPE),
 2450    MAKE_INTRINSIC_S("menu_delete_items", menu_delete_items_cmd, VOID_TYPE),
 2451    MAKE_INTRINSIC_SI("menu_set_object_available", set_object_available_cmd, VOID_TYPE),
 2452    MAKE_INTRINSIC_0("menu_set_select_menubar_callback", set_select_menubar_callback, VOID_TYPE),
 2453    MAKE_INTRINSIC_0("menu_set_init_menubar_callback", set_init_menubar_callback, VOID_TYPE),
 2454    MAKE_INTRINSIC_0("menu_set_select_popup_callback", set_select_popup_callback, VOID_TYPE),
 2455    MAKE_INTRINSIC_0("menu_set_tweak_popup_callback", set_tweak_popup_callback, VOID_TYPE),
 2456    MAKE_INTRINSIC_SS("menu_copy_menu", copy_menu_cmd, VOID_TYPE),
 2457    MAKE_INTRINSIC_SS("menu_set_menu_bar_prefix", set_menu_bar_prefix_string, VOID_TYPE),
 2458    MAKE_INTRINSIC_S("menu_select_menu", popup_menu_cmd, VOID_TYPE),
 2459    MAKE_INTRINSIC(NULL,NULL,0,0)
 2460 };
 2461 
 2462 int jed_init_menus (void)
 2463 {
 2464    if (-1 == init_menu_keymap ())
 2465      return -1;
 2466 
 2467    if (-1 == SLadd_intrin_fun_table (Menu_Table, NULL))
 2468      return -1;
 2469 #if 0
 2470    if (-1 == make_global_menubar ())
 2471      return -1;
 2472 #endif
 2473    return 0;
 2474 }
 2475 
 2476 #ifdef HAS_MOUSE
 2477 static int select_menu_via_rc (int type, int r, int c)
 2478 {
 2479    Menu_Popup_Type *p;
 2480    
 2481    p = Active_Popup;
 2482    while (p != (Menu_Popup_Type *)Active_Menu_Bar)
 2483      {
 2484     if ((r >= p->row) 
 2485         && (r < p->max_row)
 2486         && (c >= p->column)
 2487         && (c < p->max_col))
 2488       break;
 2489     
 2490     p = p->parent;
 2491      }
 2492    
 2493    if ((p == NULL) || (p->type == MENU_NODE_MENUBAR))
 2494      {
 2495     unsigned int i;
 2496     int *item_columns;
 2497 
 2498     if (Active_Popup == NULL)
 2499       return -1;
 2500     
 2501     if (r != 0)
 2502       {
 2503          if (type != JMOUSE_DRAG)
 2504            return -1;
 2505 
 2506          if (Active_Popup->type != MENU_NODE_MENUBAR)
 2507            return 0;
 2508       }
 2509     
 2510     unselect_active_node ((Menu_Popup_Type *) Active_Menu_Bar);
 2511 
 2512     i = Active_Menu_Bar->num_subnodes;
 2513     item_columns = Active_Menu_Bar->item_columns;
 2514     while (i > 0)
 2515       {
 2516          i--;
 2517 
 2518          if ((i != 0) && (item_columns[i] > c))
 2519            continue;
 2520 
 2521          p = (Menu_Popup_Type *)Active_Menu_Bar->subnodes[i];
 2522          if (p->type == MENU_NODE_SEPARATOR)
 2523            continue;
 2524           
 2525          if (p->flags & MENU_ITEM_UNAVAILABLE)
 2526            continue;
 2527 
 2528          if (-1 == set_node_selection ((Menu_Popup_Type *) Active_Menu_Bar,
 2529                        (Menu_Node_Type *) p))
 2530            return -1;
 2531          
 2532          if (-1 == find_active_popup ())
 2533            return -1;
 2534 
 2535          if (p->type == MENU_NODE_POPUP)
 2536            return select_menu_cmd ();
 2537       }
 2538     return -1;
 2539      }
 2540  
 2541    if (p == Active_Popup)
 2542      {
 2543     r -= (p->row + 1);
 2544     r += p->visible_node_offset;
 2545     if ((r >= (int)p->num_subnodes) || (r < 0))
 2546       return 0;
 2547     
 2548     if (-1 == set_node_selection (p, p->subnodes[r]))
 2549       return 0;
 2550     
 2551     if ((type != JMOUSE_DRAG)
 2552         || ((p->subnodes[r]->type == MENU_NODE_POPUP)
 2553         && (c + 1 >= p->max_col)))
 2554       select_menu_cmd ();
 2555 
 2556     return 0;
 2557      }
 2558    
 2559    while (Active_Popup != p)
 2560      back_menu_cmd ();
 2561 
 2562    return 0;
 2563 }
 2564 
 2565 int jed_menu_handle_mouse (unsigned int type, 
 2566                int x, int y, int button, int shift)
 2567 {
 2568    (void) shift; (void) button;
 2569 
 2570    if ((type != JMOUSE_UP) && (type != JMOUSE_DRAG))
 2571      return -1;
 2572 
 2573    if ((Jed_Menus_Active == 0)
 2574        && (-1 == jed_select_menu_bar ()))
 2575      return -1;
 2576 
 2577    if (-1 == select_menu_via_rc (type, y-1, x-1))
 2578      {
 2579     if (type != JMOUSE_DRAG)
 2580       jed_exit_menu_bar ();
 2581      }
 2582 
 2583    return 0;
 2584 }
 2585 
 2586 #ifndef IBMPC_SYSTEM
 2587 static int xterm_mouse_cmd (void)
 2588 {
 2589    int x, y, b;
 2590    
 2591    b = my_getkey ();
 2592    x = (unsigned char) my_getkey () - 32;
 2593    y = (unsigned char) my_getkey () - 32;
 2594    
 2595    /* We need to trigger on the button release event */
 2596    
 2597    b -= 32;
 2598    if ((b & 3) != 3)
 2599      return -1;
 2600    
 2601    return jed_menu_handle_mouse (JMOUSE_UP, x, y, 0, 0);
 2602 }
 2603 
 2604 
 2605 #endif                     /* !IBMPC_SYSTEM */
 2606 #endif                     /* HAS_MOUSE */
 2607 #endif                     /* JED_HAS_MENUS */