emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: NT Emacs crashes when selecting a menubar item


From: David Ponce
Subject: Re: NT Emacs crashes when selecting a menubar item
Date: Sun, 28 Jul 2002 18:56:55 +0200
User-agent: Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.1b) Gecko/20020720

Hi Richard,

You have made significant progress, but we don't know the answer yet.

Can you determine where that data becomes corrupted?
Is it written wrong at the start, or does it get
clobbered later on?


Thank you for your support!

I worked hard to find the bug that corrupted menu strings, and I
think I finally found it!

In fact, after displaying memory locations of menu item strings in
`widget_value' data structures, I noticed that sometimes their
contents changed (not the location) between their initialization in
`single_submenu' and their use in `add_menu_item'.

This looked like a bad interaction with GC.  I carefully reviewed the
code and was first disappointed because all the Lisp strings that
produced menu item strings seemed correctly protected from GC!  I
looked more thoroughly at the GC code, and discovered that the data
part of Lisp strings may be relocated when GC compacts the Lisp string
storage.  Even when the base string Lisp_Object is protected!

So, I hacked w32menu.c to used safe local copy of menu item strings,
and the bug disappeared :-)

From that base, I took time to properly update w32menu.c, and fixed
another bug too, related to pop up menu cleanup.  Finally I cleaned
up the code to generalize use of AREF, ASET and ASIZE macros.

Attached you will find the patch, the change log is at end.

With the patch menus work very well now, with no noticeable slow down
(I used the faster Win32 API to alloc/free memory).

I don't know if it is possible, or if that could solve such problems
(is it guaranteed that GC can't raise when a menu is showing up?),
but perhaps a more general solution, probably with more impact, would
be to directly use Lisp strings in `widget_value', like for help
items?

What do you think?

Sincerely,
David

------------------------ Change Log --------------------------------
(local_heap, local_alloc, local_free): New macros.
(malloc_widget_value, free_widget_value)
(free_menubar_widget_value_tree)
(w32_free_submenu_strings): Use them.

(local-string): New function.
(single_submenu, set_frame_menubar)
(w32_menu_show, add_menu_item): Use it.

(push_submenu_start, push_submenu_end, push_left_right_boundary)
(push_menu_pane, push_menu_item, single_keymap_panes)
(single_menu_item, Fx_popup_menu, menubar_selection_callback)
(single_submenu, set_frame_menubar)
(w32_menu_show, w32_dialog_show): Use AREF, ASET, ASIZE.

(Fx_popup_menu):  Don't show pop up menu until preceding one is
actually cleaned up.  Moved UNGCPRO outside #ifdef HAVE_MENUS block.

*** w32menu.c.ori       Mon Jul 15 10:48:32 2002
--- w32menu.c   Sun Jul 28 18:35:13 2002
***************
*** 112,120 ****
  #endif
  } widget_value;
  
! /* LocalAlloc/Free is a reasonably good allocator.  */
! #define malloc_widget_value() (void*)LocalAlloc (LMEM_ZEROINIT, sizeof 
(widget_value))
! #define free_widget_value(wv) LocalFree (wv)
  
  /******************************************************************/
  
--- 112,124 ----
  #endif
  } widget_value;
  
! /* Local memory management */
! #define local_heap (GetProcessHeap ())
! #define local_alloc(n) (HeapAlloc (local_heap, HEAP_ZERO_MEMORY, (n)))
! #define local_free(p) (HeapFree (local_heap, 0, ((LPVOID) (p))))
! 
! #define malloc_widget_value() ((widget_value *) local_alloc (sizeof 
(widget_value)))
! #define free_widget_value(wv) (local_free ((wv)))
  
  /******************************************************************/
  
***************
*** 318,324 ****
    if (menu_items_used + 1 > menu_items_allocated)
      grow_menu_items ();
  
!   XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
    menu_items_submenu_depth++;
  }
  
--- 322,328 ----
    if (menu_items_used + 1 > menu_items_allocated)
      grow_menu_items ();
  
!   ASET (menu_items, menu_items_used++, Qnil);
    menu_items_submenu_depth++;
  }
  
***************
*** 330,336 ****
    if (menu_items_used + 1 > menu_items_allocated)
      grow_menu_items ();
  
!   XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
    menu_items_submenu_depth--;
  }
  
--- 334,340 ----
    if (menu_items_used + 1 > menu_items_allocated)
      grow_menu_items ();
  
!   ASET (menu_items, menu_items_used++, Qlambda);
    menu_items_submenu_depth--;
  }
  
***************
*** 342,348 ****
    if (menu_items_used + 1 > menu_items_allocated)
      grow_menu_items ();
  
!   XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
  }
  
  /* Start a new menu pane in menu_items.
--- 346,352 ----
    if (menu_items_used + 1 > menu_items_allocated)
      grow_menu_items ();
  
!   ASET (menu_items, menu_items_used++, Qquote);
  }
  
  /* Start a new menu pane in menu_items.
***************
*** 357,365 ****
  
    if (menu_items_submenu_depth == 0)
      menu_items_n_panes++;
!   XVECTOR (menu_items)->contents[menu_items_used++] = Qt;
!   XVECTOR (menu_items)->contents[menu_items_used++] = name;
!   XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
  }
  
  /* Push one menu item into the current pane.  NAME is the string to
--- 361,369 ----
  
    if (menu_items_submenu_depth == 0)
      menu_items_n_panes++;
!   ASET (menu_items, menu_items_used++, Qt);
!   ASET (menu_items, menu_items_used++, name);
!   ASET (menu_items, menu_items_used++, prefix_vec);
  }
  
  /* Push one menu item into the current pane.  NAME is the string to
***************
*** 377,390 ****
    if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
      grow_menu_items ();
  
!   XVECTOR (menu_items)->contents[menu_items_used++] = name;
!   XVECTOR (menu_items)->contents[menu_items_used++] = enable;
!   XVECTOR (menu_items)->contents[menu_items_used++] = key;
!   XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
!   XVECTOR (menu_items)->contents[menu_items_used++] = def;
!   XVECTOR (menu_items)->contents[menu_items_used++] = type;
!   XVECTOR (menu_items)->contents[menu_items_used++] = selected;
!   XVECTOR (menu_items)->contents[menu_items_used++] = help;
  }
  
  /* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
--- 381,394 ----
    if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
      grow_menu_items ();
  
!   ASET (menu_items, menu_items_used++, name);
!   ASET (menu_items, menu_items_used++, enable);
!   ASET (menu_items, menu_items_used++, key);
!   ASET (menu_items, menu_items_used++, equiv);
!   ASET (menu_items, menu_items_used++, def);
!   ASET (menu_items, menu_items_used++, type);
!   ASET (menu_items, menu_items_used++, selected);
!   ASET (menu_items, menu_items_used++, help);
  }
  
  /* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
***************
*** 450,462 ****
        else if (VECTORP (item))
        {
          /* Loop over the char values represented in the vector.  */
!         int len = XVECTOR (item)->size;
          int c;
          for (c = 0; c < len; c++)
            {
              Lisp_Object character;
              XSETFASTINT (character, c);
!             single_menu_item (character, XVECTOR (item)->contents[c],
                                &pending_maps, notreal, maxdepth);
            }
        }
--- 454,466 ----
        else if (VECTORP (item))
        {
          /* Loop over the char values represented in the vector.  */
!         int len = ASIZE (item);
          int c;
          for (c = 0; c < len; c++)
            {
              Lisp_Object character;
              XSETFASTINT (character, c);
!             single_menu_item (character, AREF (item, c),
                                &pending_maps, notreal, maxdepth);
            }
        }
***************
*** 504,510 ****
    if (!res)
      return;                   /* Not a menu item.  */
  
!   map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
    
    if (notreal)
      {
--- 508,514 ----
    if (!res)
      return;                   /* Not a menu item.  */
  
!   map = AREF (item_properties, ITEM_PROPERTY_MAP);
    
    if (notreal)
      {
***************
*** 515,522 ****
        return;
      }
  
!   enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
!   item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME]; 
  
    if (!NILP (map) && SREF (item_string, 0) == '@')
      {
--- 519,526 ----
        return;
      }
  
!   enabled = AREF (item_properties, ITEM_PROPERTY_ENABLE);
!   item_string = AREF (item_properties, ITEM_PROPERTY_NAME); 
  
    if (!NILP (map) && SREF (item_string, 0) == '@')
      {
***************
*** 528,538 ****
      }
  
    push_menu_item (item_string, enabled, key,
!                 XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF],
!                 XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ],
!                 XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE],
!                   XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
!                   XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
  
    /* Display a submenu using the toolkit.  */
    if (! (NILP (map) || NILP (enabled)))
--- 532,542 ----
      }
  
    push_menu_item (item_string, enabled, key,
!                 AREF (item_properties, ITEM_PROPERTY_DEF),
!                 AREF (item_properties, ITEM_PROPERTY_KEYEQ),
!                 AREF (item_properties, ITEM_PROPERTY_TYPE),
!                   AREF (item_properties, ITEM_PROPERTY_SELECTED),
!                   AREF (item_properties, ITEM_PROPERTY_HELP));
  
    /* Display a submenu using the toolkit.  */
    if (! (NILP (map) || NILP (enabled)))
***************
*** 745,751 ****
  
        /* Make that be the pane title of the first pane.  */
        if (!NILP (prompt) && menu_items_n_panes >= 0)
!       XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = prompt;
  
        keymaps = 1;
      }
--- 749,755 ----
  
        /* Make that be the pane title of the first pane.  */
        if (!NILP (prompt) && menu_items_n_panes >= 0)
!       ASET (menu_items, MENU_ITEMS_PANE_NAME, prompt);
  
        keymaps = 1;
      }
***************
*** 777,783 ****
  
        /* Make the title be the pane title of the first pane.  */
        if (!NILP (title) && menu_items_n_panes >= 0)
!       XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title;
  
        keymaps = 1;
      }
--- 781,787 ----
  
        /* Make the title be the pane title of the first pane.  */
        if (!NILP (title) && menu_items_n_panes >= 0)
!       ASET (menu_items, MENU_ITEMS_PANE_NAME, title);
  
        keymaps = 1;
      }
***************
*** 800,805 ****
--- 804,819 ----
      }
  
  #ifdef HAVE_MENUS
+   /* If resources from a previous popup menu exist yet, does nothing
+      until the `menu_free_timer' has freed them (see w32fns.c).
+   */
+   if (current_popup_menu)
+     {
+       discard_menu_items ();
+       UNGCPRO;
+       return Qnil;
+     }    
+   
    /* Display them in a menu.  */
    BLOCK_INPUT;
  
***************
*** 808,816 ****
    UNBLOCK_INPUT;
  
    discard_menu_items ();
  
    UNGCPRO;
- #endif /* HAVE_MENUS */
  
    if (error_name) error (error_name);
    return selection;
--- 822,830 ----
    UNBLOCK_INPUT;
  
    discard_menu_items ();
+ #endif /* HAVE_MENUS */
  
    UNGCPRO;
  
    if (error_name) error (error_name);
    return selection;
***************
*** 981,1005 ****
    i = 0;
    while (i < f->menu_bar_items_used)
      {
!       if (EQ (XVECTOR (vector)->contents[i], Qnil))
        {
          subprefix_stack[submenu_depth++] = prefix;
          prefix = entry;
          i++;
        }
!       else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
        {
          prefix = subprefix_stack[--submenu_depth];
          i++;
        }
!       else if (EQ (XVECTOR (vector)->contents[i], Qt))
        {
!         prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
          i += MENU_ITEMS_PANE_LENGTH;
        }
        else
        {
!         entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
          /* The EMACS_INT cast avoids a warning.  There's no problem
             as long as pointers have enough bits to hold small integers.  */
          if ((int) (EMACS_INT) client_data == i)
--- 995,1019 ----
    i = 0;
    while (i < f->menu_bar_items_used)
      {
!       if (EQ (AREF (vector, i), Qnil))
        {
          subprefix_stack[submenu_depth++] = prefix;
          prefix = entry;
          i++;
        }
!       else if (EQ (AREF (vector, i), Qlambda))
        {
          prefix = subprefix_stack[--submenu_depth];
          i++;
        }
!       else if (EQ (AREF (vector, i), Qt))
        {
!         prefix = AREF (vector, i + MENU_ITEMS_PANE_PREFIX);
          i += MENU_ITEMS_PANE_LENGTH;
        }
        else
        {
!         entry = AREF (vector, i + MENU_ITEMS_ITEM_VALUE);
          /* The EMACS_INT cast avoids a warning.  There's no problem
             as long as pointers have enough bits to hold small integers.  */
          if ((int) (EMACS_INT) client_data == i)
***************
*** 1051,1056 ****
--- 1065,1089 ----
    f->output_data.w32->menubar_active = 0;
  }
  
+ /* Return a local copy of the given input string STR.
+    Does nothing if STR is 0.
+    
+    It is necessary to use safe local copy of string data stored in
+    widget_value because the data part of Lisp strings can be relocated
+    when the GC compacts string storage.  Even when the base string
+    Lisp_Object is protected!  */
+ char *
+ local_string (const char *str)
+ {
+   if (str)
+     {
+       char *clone = (char *) local_alloc (strlen (str) + 1);
+       strcpy (clone, str);
+       return clone;
+     }
+   return 0;
+ }
+ 
  /* Allocate a widget_value, blocking input.  */
  
  widget_value *
***************
*** 1075,1081 ****
       widget_value *wv;
  {
    if (! wv) return;
! 
    wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
  
    if (wv->contents && (wv->contents != (widget_value*)1))
--- 1108,1118 ----
       widget_value *wv;
  {
    if (! wv) return;
!   
!   local_free (wv->name);
!   local_free (wv->value);
!   local_free (wv->key);
!   
    wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
  
    if (wv->contents && (wv->contents != (widget_value*)1))
***************
*** 1148,1154 ****
    submenu_stack
      = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
    wv = xmalloc_widget_value ();
!   wv->name = "menu";
    wv->value = 0;
    wv->enabled = 1;
    wv->button_type = BUTTON_TYPE_NONE;
--- 1185,1191 ----
    submenu_stack
      = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
    wv = xmalloc_widget_value ();
!   wv->name = local_string ("menu");
    wv->value = 0;
    wv->enabled = 1;
    wv->button_type = BUTTON_TYPE_NONE;
***************
*** 1164,1203 ****
    i = previous_items;
    while (i < menu_items_used)
      {
!       if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
        {
          submenu_stack[submenu_depth++] = save_wv;
          save_wv = prev_wv;
          prev_wv = 0;
          i++;
        }
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
        {
          prev_wv = save_wv;
          save_wv = submenu_stack[--submenu_depth];
          i++;
        }
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
               && submenu_depth != 0)
        i += MENU_ITEMS_PANE_LENGTH;
        /* Ignore a nil in the item list.
         It's meaningful only for dialog boxes.  */
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
        i += 1;
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
        {
          /* Create a new pane.  */
          Lisp_Object pane_name, prefix;
          char *pane_string;
  
!         pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
!         prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
  
  #ifndef HAVE_MULTILINGUAL_MENU
          if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
            {
              pane_name = ENCODE_SYSTEM (pane_name);
!             AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
            }
  #endif
          pane_string = (NILP (pane_name)
--- 1201,1240 ----
    i = previous_items;
    while (i < menu_items_used)
      {
!       if (EQ (AREF (menu_items, i), Qnil))
        {
          submenu_stack[submenu_depth++] = save_wv;
          save_wv = prev_wv;
          prev_wv = 0;
          i++;
        }
!       else if (EQ (AREF (menu_items, i), Qlambda))
        {
          prev_wv = save_wv;
          save_wv = submenu_stack[--submenu_depth];
          i++;
        }
!       else if (EQ (AREF (menu_items, i), Qt)
               && submenu_depth != 0)
        i += MENU_ITEMS_PANE_LENGTH;
        /* Ignore a nil in the item list.
         It's meaningful only for dialog boxes.  */
!       else if (EQ (AREF (menu_items, i), Qquote))
        i += 1;
!       else if (EQ (AREF (menu_items, i), Qt))
        {
          /* Create a new pane.  */
          Lisp_Object pane_name, prefix;
          char *pane_string;
  
!         pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
!         prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
  
  #ifndef HAVE_MULTILINGUAL_MENU
          if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
            {
              pane_name = ENCODE_SYSTEM (pane_name);
!             ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
            }
  #endif
          pane_string = (NILP (pane_name)
***************
*** 1222,1227 ****
--- 1259,1265 ----
                 This is a kludge, but this isn't worth more time.  */
              if (!NILP (prefix) && wv->name[0] == '@')
                wv->name++;
+               wv->name = local_string (wv->name);
              wv->value = 0;
              wv->enabled = 1;
              wv->button_type = BUTTON_TYPE_NONE;
***************
*** 1249,1261 ****
          if (STRING_MULTIBYTE (item_name))
            {
              item_name = ENCODE_SYSTEM (item_name);
!             AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
            }
  
          if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
            {
              descrip = ENCODE_SYSTEM (descrip);
!             AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
            }
  #endif /* not HAVE_MULTILINGUAL_MENU */
  
--- 1287,1299 ----
          if (STRING_MULTIBYTE (item_name))
            {
              item_name = ENCODE_SYSTEM (item_name);
!             ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
            }
  
          if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
            {
              descrip = ENCODE_SYSTEM (descrip);
!             ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
            }
  #endif /* not HAVE_MULTILINGUAL_MENU */
  
***************
*** 1265,1273 ****
          else
            save_wv->contents = wv;
  
!         wv->name = (char *) SDATA (item_name);
          if (!NILP (descrip))
!           wv->key = (char *) SDATA (descrip);
          wv->value = 0;
          /* The EMACS_INT cast avoids a warning.  There's no problem
             as long as pointers have enough bits to hold small integers.  */
--- 1303,1311 ----
          else
            save_wv->contents = wv;
  
!         wv->name = local_string ((char *) SDATA (item_name));
          if (!NILP (descrip))
!           wv->key = local_string ((char *) SDATA (descrip));
          wv->value = 0;
          /* The EMACS_INT cast avoids a warning.  There's no problem
             as long as pointers have enough bits to hold small integers.  */
***************
*** 1334,1340 ****
      deep_p = 1;
  
    wv = xmalloc_widget_value ();
!   wv->name = "menubar";
    wv->value = 0;
    wv->enabled = 1;
    wv->button_type = BUTTON_TYPE_NONE;
--- 1372,1378 ----
      deep_p = 1;
  
    wv = xmalloc_widget_value ();
!   wv->name = local_string ("menubar");
    wv->value = 0;
    wv->enabled = 1;
    wv->button_type = BUTTON_TYPE_NONE;
***************
*** 1395,1407 ****
        menu_items = f->menu_bar_vector;
        menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
        init_menu_items ();
!       for (i = 0; i < XVECTOR (items)->size; i += 4)
        {
          Lisp_Object key, string, maps;
  
!         key = XVECTOR (items)->contents[i];
!         string = XVECTOR (items)->contents[i + 1];
!         maps = XVECTOR (items)->contents[i + 2];
          if (NILP (string))
            break;
  
--- 1433,1445 ----
        menu_items = f->menu_bar_vector;
        menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
        init_menu_items ();
!       for (i = 0; i < ASIZE (items); i += 4)
        {
          Lisp_Object key, string, maps;
  
!         key = AREF (items, i);
!         string = AREF (items, i + 1);
!         maps = AREF (items, i + 2);
          if (NILP (string))
            break;
  
***************
*** 1426,1432 ****
  
        for (i = 0; i < previous_menu_items_used; i++)
        if (menu_items_used == i
!           || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
          break;
        if (i == menu_items_used && i == previous_menu_items_used && i != 0)
        {
--- 1464,1470 ----
  
        for (i = 0; i < previous_menu_items_used; i++)
        if (menu_items_used == i
!           || (!EQ (previous_items[i], AREF (menu_items, i))))
          break;
        if (i == menu_items_used && i == previous_menu_items_used && i != 0)
        {
***************
*** 1442,1454 ****
         Windows takes care of this for normal string items, but
         not for owner-drawn items or additional item-info.  */
        wv = first_wv->contents;
!       for (i = 0; i < XVECTOR (items)->size; i += 4)
        {
          Lisp_Object string;
!         string = XVECTOR (items)->contents[i + 1];
          if (NILP (string))
            break;
!         wv->name = (char *) SDATA (string);
          wv = wv->next;
        }
  
--- 1480,1492 ----
         Windows takes care of this for normal string items, but
         not for owner-drawn items or additional item-info.  */
        wv = first_wv->contents;
!       for (i = 0; i < ASIZE (items); i += 4)
        {
          Lisp_Object string;
!         string = AREF (items, i + 1);
          if (NILP (string))
            break;
!         wv->name = local_string ((char *) SDATA (string));
          wv = wv->next;
        }
  
***************
*** 1462,1477 ****
         just the top level menu bar strings.  */
  
        items = FRAME_MENU_BAR_ITEMS (f);
!       for (i = 0; i < XVECTOR (items)->size; i += 4)
        {
          Lisp_Object string;
  
!         string = XVECTOR (items)->contents[i + 1];
          if (NILP (string))
            break;
  
          wv = xmalloc_widget_value ();
!         wv->name = (char *) SDATA (string);
          wv->value = 0;
          wv->enabled = 1;
          wv->button_type = BUTTON_TYPE_NONE;
--- 1500,1515 ----
         just the top level menu bar strings.  */
  
        items = FRAME_MENU_BAR_ITEMS (f);
!       for (i = 0; i < ASIZE (items); i += 4)
        {
          Lisp_Object string;
  
!         string = AREF (items, i + 1);
          if (NILP (string))
            break;
  
          wv = xmalloc_widget_value ();
!         wv->name = local_string ((char *) SDATA (string));
          wv->value = 0;
          wv->enabled = 1;
          wv->button_type = BUTTON_TYPE_NONE;
***************
*** 1613,1619 ****
    /* Create a tree of widget_value objects
       representing the panes and their items.  */
    wv = xmalloc_widget_value ();
!   wv->name = "menu";
    wv->value = 0;
    wv->enabled = 1;
    wv->button_type = BUTTON_TYPE_NONE;
--- 1651,1657 ----
    /* Create a tree of widget_value objects
       representing the panes and their items.  */
    wv = xmalloc_widget_value ();
!   wv->name = local_string ("menu");
    wv->value = 0;
    wv->enabled = 1;
    wv->button_type = BUTTON_TYPE_NONE;
***************
*** 1625,1631 ****
    i = 0;
    while (i < menu_items_used)
      {
!       if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
        {
          submenu_stack[submenu_depth++] = save_wv;
          save_wv = prev_wv;
--- 1663,1669 ----
    i = 0;
    while (i < menu_items_used)
      {
!       if (EQ (AREF (menu_items, i), Qnil))
        {
          submenu_stack[submenu_depth++] = save_wv;
          save_wv = prev_wv;
***************
*** 1633,1653 ****
          first_pane = 1;
          i++;
        }
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
        {
          prev_wv = save_wv;
          save_wv = submenu_stack[--submenu_depth];
          first_pane = 0;
          i++;
        }
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
               && submenu_depth != 0)
        i += MENU_ITEMS_PANE_LENGTH;
        /* Ignore a nil in the item list.
         It's meaningful only for dialog boxes.  */
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
        i += 1;
!       else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
        {
          /* Create a new pane.  */
          Lisp_Object pane_name, prefix;
--- 1671,1691 ----
          first_pane = 1;
          i++;
        }
!       else if (EQ (AREF (menu_items, i), Qlambda))
        {
          prev_wv = save_wv;
          save_wv = submenu_stack[--submenu_depth];
          first_pane = 0;
          i++;
        }
!       else if (EQ (AREF (menu_items, i), Qt)
               && submenu_depth != 0)
        i += MENU_ITEMS_PANE_LENGTH;
        /* Ignore a nil in the item list.
         It's meaningful only for dialog boxes.  */
!       else if (EQ (AREF (menu_items, i), Qquote))
        i += 1;
!       else if (EQ (AREF (menu_items, i), Qt))
        {
          /* Create a new pane.  */
          Lisp_Object pane_name, prefix;
***************
*** 1658,1664 ****
          if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
            {
              pane_name = ENCODE_SYSTEM (pane_name);
!             AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
            }
  #endif
          pane_string = (NILP (pane_name)
--- 1696,1702 ----
          if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
            {
              pane_name = ENCODE_SYSTEM (pane_name);
!             ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
            }
  #endif
          pane_string = (NILP (pane_name)
***************
*** 1681,1686 ****
--- 1719,1725 ----
              wv->name = pane_string;
              if (keymaps && !NILP (prefix))
                wv->name++;
+               wv->name = local_string (wv->name);
              wv->value = 0;
              wv->enabled = 1;
              wv->button_type = BUTTON_TYPE_NONE;
***************
*** 1713,1724 ****
            if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
            {
              item_name = ENCODE_SYSTEM (item_name);
!             AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
            }
            if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
              {
              descrip = ENCODE_SYSTEM (descrip);
!             AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
            }
  #endif /* not HAVE_MULTILINGUAL_MENU */
  
--- 1752,1763 ----
            if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
            {
              item_name = ENCODE_SYSTEM (item_name);
!             ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
            }
            if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
              {
              descrip = ENCODE_SYSTEM (descrip);
!             ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
            }
  #endif /* not HAVE_MULTILINGUAL_MENU */
  
***************
*** 1727,1735 ****
            prev_wv->next = wv;
          else 
            save_wv->contents = wv;
!         wv->name = (char *) SDATA (item_name);
          if (!NILP (descrip))
!           wv->key = (char *) SDATA (descrip);
          wv->value = 0;
          /* Use the contents index as call_data, since we are
               restricted to 16-bits.  */
--- 1766,1774 ----
            prev_wv->next = wv;
          else 
            save_wv->contents = wv;
!         wv->name = local_string ((char *) SDATA (item_name));
          if (!NILP (descrip))
!           wv->key = local_string ((char *) SDATA (descrip));
          wv->value = 0;
          /* Use the contents index as call_data, since we are
               restricted to 16-bits.  */
***************
*** 1765,1771 ****
  
        /* Maybe replace this separator with a bitmap or owner-draw item
         so that it looks better.  Having two separators looks odd.  */
!       wv_sep->name = "--";
        wv_sep->next = first_wv->contents;
        wv_sep->help = Qnil;
  
--- 1804,1810 ----
  
        /* Maybe replace this separator with a bitmap or owner-draw item
         so that it looks better.  Having two separators looks odd.  */
!       wv_sep->name = local_string ("--");
        wv_sep->next = first_wv->contents;
        wv_sep->help = Qnil;
  
***************
*** 1773,1779 ****
        if (STRING_MULTIBYTE (title))
        title = ENCODE_SYSTEM (title);
  #endif
!       wv_title->name = (char *) SDATA (title);
        wv_title->enabled = TRUE;
        wv_title->title = TRUE;
        wv_title->button_type = BUTTON_TYPE_NONE;
--- 1812,1818 ----
        if (STRING_MULTIBYTE (title))
        title = ENCODE_SYSTEM (title);
  #endif
!       wv_title->name = local_string ((char *) SDATA (title));
        wv_title->enabled = TRUE;
        wv_title->title = TRUE;
        wv_title->button_type = BUTTON_TYPE_NONE;
***************
*** 1818,1848 ****
        i = 0;
        while (i < menu_items_used)
        {
!         if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
            {
              subprefix_stack[submenu_depth++] = prefix;
              prefix = entry;
              i++;
            }
!         else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
            {
              prefix = subprefix_stack[--submenu_depth];
              i++;
            }
!         else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
            {
!             prefix
!               = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
              i += MENU_ITEMS_PANE_LENGTH;
            }
          /* Ignore a nil in the item list.
             It's meaningful only for dialog boxes.  */
!         else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
            i += 1;
          else
            {
!             entry
!               = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
              if (menu_item_selection == i)
                {
                  if (keymaps != 0)
--- 1857,1885 ----
        i = 0;
        while (i < menu_items_used)
        {
!         if (EQ (AREF (menu_items, i), Qnil))
            {
              subprefix_stack[submenu_depth++] = prefix;
              prefix = entry;
              i++;
            }
!         else if (EQ (AREF (menu_items, i), Qlambda))
            {
              prefix = subprefix_stack[--submenu_depth];
              i++;
            }
!         else if (EQ (AREF (menu_items, i), Qt))
            {
!             prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
              i += MENU_ITEMS_PANE_LENGTH;
            }
          /* Ignore a nil in the item list.
             It's meaningful only for dialog boxes.  */
!         else if (EQ (AREF (menu_items, i), Qquote))
            i += 1;
          else
            {
!             entry     = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
              if (menu_item_selection == i)
                {
                  if (keymaps != 0)
***************
*** 1903,1910 ****
    {
      Lisp_Object pane_name, prefix;
      char *pane_string;
!     pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
!     prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
      pane_string = (NILP (pane_name)
                   ? "" : (char *) SDATA (pane_name));  
      prev_wv = xmalloc_widget_value ();
--- 1940,1947 ----
    {
      Lisp_Object pane_name, prefix;
      char *pane_string;
!     pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
!     prefix = AREF (menu_items, MENU_ITEMS_PANE_PREFIX);
      pane_string = (NILP (pane_name)
                   ? "" : (char *) SDATA (pane_name));  
      prev_wv = xmalloc_widget_value ();
***************
*** 1924,1934 ****
        /* Create a new item within current pane.  */
        Lisp_Object item_name, enable, descrip, help;
  
!       item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
!       enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
!       descrip
!         = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
!         help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
        
        if (NILP (item_name))
          {
--- 1961,1970 ----
        /* Create a new item within current pane.  */
        Lisp_Object item_name, enable, descrip, help;
  
!       item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
!       enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
!       descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
!         help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
        
        if (NILP (item_name))
          {
***************
*** 1957,1963 ****
        if (!NILP (descrip))
          wv->key = (char *) SDATA (descrip);
        wv->value = (char *) SDATA (item_name);
!       wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
        wv->enabled = !NILP (enable);
        wv->help = Qnil;
        prev_wv = wv;
--- 1993,1999 ----
        if (!NILP (descrip))
          wv->key = (char *) SDATA (descrip);
        wv->value = (char *) SDATA (item_name);
!       wv->call_data = (void *) &AREF (menu_items, i);
        wv->enabled = !NILP (enable);
        wv->help = Qnil;
        prev_wv = wv;
***************
*** 2027,2042 ****
        {
          Lisp_Object entry;
  
!         if (EQ (XVECTOR (menu_items)->contents[i], Qt))
            {
!             prefix
!               = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
              i += MENU_ITEMS_PANE_LENGTH;
            }
          else
            {
!             entry
!               = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
              if (menu_item_selection == i)
                {
                  if (keymaps != 0)
--- 2063,2076 ----
        {
          Lisp_Object entry;
  
!         if (EQ (AREF (menu_items, i), Qt))
            {
!             prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
              i += MENU_ITEMS_PANE_LENGTH;
            }
          else
            {
!             entry     = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
              if (menu_item_selection == i)
                {
                  if (keymaps != 0)
***************
*** 2117,2127 ****
             we can't deallocate the memory otherwise.  */
          if (get_menu_item_info)
            {
!             out_string = (char *) LocalAlloc (LPTR, strlen (wv->name) + 1);
  #ifdef MENU_DEBUG
!             DebPrint ("Menu: allocing %ld for owner-draw", info.dwItemData);
  #endif
-             strcpy (out_string, wv->name);
              fuFlags = MF_OWNERDRAW | MF_DISABLED;
            }
          else
--- 2151,2160 ----
             we can't deallocate the memory otherwise.  */
          if (get_menu_item_info)
            {
!             out_string = local_string (wv->name);
  #ifdef MENU_DEBUG
!             DebPrint ("Menu: allocing %ld for owner-draw", out_string);
  #endif
              fuFlags = MF_OWNERDRAW | MF_DISABLED;
            }
          else
***************
*** 2277,2283 ****
  #ifdef MENU_DEBUG
          DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData);
  #endif
!         LocalFree (info.dwItemData);
        }
  
        /* Recurse down submenus.  */
--- 2310,2316 ----
  #ifdef MENU_DEBUG
          DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData);
  #endif
!         local_free (info.dwItemData);
        }
  
        /* Recurse down submenus.  */

reply via email to

[Prev in Thread] Current Thread [Next in Thread]