unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: David Ponce <david@dponce.com>
Cc: emacs-devel@gnu.org
Subject: Re: NT Emacs crashes when selecting a menubar item
Date: Sun, 28 Jul 2002 18:56:55 +0200	[thread overview]
Message-ID: <3D442257.8000602@dponce.com> (raw)
In-Reply-To: 200207271852.g6RIqmA10723@aztec.santafe.edu

[-- Attachment #1: Type: text/plain, Size: 2537 bytes --]

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.


[-- Attachment #2: w32menu.patch --]
[-- Type: text/x-patch, Size: 31233 bytes --]

*** 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;
  }
  \f
  /* 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);
  }
  \f
  /* 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	other threads:[~2002-07-28 16:56 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-07-24 18:55 NT Emacs crashes when selecting a menubar item David Ponce
2002-07-25 18:07 ` Richard Stallman
2002-07-26 12:30   ` David Ponce
2002-07-27 18:52     ` Richard Stallman
2002-07-28 16:56       ` David Ponce [this message]
2002-07-29 17:30         ` Richard Stallman
2002-07-29 18:16           ` David Ponce
2002-07-30 18:46             ` Richard Stallman
  -- strict thread matches above, loose matches on Subject: below --
2002-07-30 11:28 David PONCE
     [not found] <3D2A791A00A0862A@mel-rta9.wanadoo.fr>
2002-07-31 21:57 ` Richard Stallman
2002-07-31 22:37   ` David Ponce
2002-08-01  7:54 jasonr
2002-08-01 11:39 David PONCE

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3D442257.8000602@dponce.com \
    --to=david@dponce.com \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).