changeset 41908:4d8905b9ee49

(_widget_value): Make `help' field a Lisp_Object. Add comment to explain where the struct came from. (single_submenu, w32_menu_show): Set `help' field as Lisp_Object. (add_menu_item): Process pop-up menus first to avoid memory leak. (add_menu_item, w32_menu_display_help): Use `help' field as Lisp_Object. (w32_free_submenu_strings): Only free owner-drawn strings.
author Jason Rumney <jasonr@gnu.org>
date Sun, 09 Dec 2001 16:48:03 +0000
parents bb217edc49d0
children 59c24fd13803
files src/w32menu.c
diffstat 1 files changed, 36 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/src/w32menu.c	Sun Dec 09 16:47:16 2001 +0000
+++ b/src/w32menu.c	Sun Dec 09 16:48:03 2001 +0000
@@ -61,6 +61,8 @@
   BUTTON_TYPE_RADIO
 };
 
+/* This structure is based on the one in ../lwlib/lwlib.h, modified
+   for Windows.  */
 typedef struct _widget_value
 {
   /* name of widget */
@@ -69,8 +71,10 @@
   char*		value;
   /* keyboard equivalent. no implications for XtTranslations */ 
   char*		key;
-  /* Help string or null if none.  */
-  char		*help;
+  /* Help string or nil if none.
+     GC finds this string through the frame's menu_bar_vector
+     or through menu_items.  */
+  Lisp_Object	help;
   /* true if enabled */
   Boolean	enabled;
   /* true if selected */
@@ -1269,10 +1273,10 @@
 	    abort ();
 
 	  wv->selected = !NILP (selected);
-	  if (STRINGP (help))
-	    wv->help = (char *) XSTRING (help)->data;
-          else
-            wv->help = NULL;
+	  if (!STRINGP (help))
+	    help = Qnil;
+
+	  wv->help = help;
 
 	  prev_wv = wv;
 
@@ -1727,8 +1731,10 @@
 	    abort ();
 
 	  wv->selected = !NILP (selected);
-          if (STRINGP (help))
-            wv->help = XSTRING (help)->data;
+          if (!STRINGP (help))
+	    help = Qnil;
+
+	  wv->help = help;
 
 	  prev_wv = wv;
 
@@ -2083,13 +2089,18 @@
       else
 	out_string = wv->name;
 
-      if (wv->title || wv->call_data == 0)
+      if (item != NULL)
+	fuFlags = MF_POPUP;
+      else if (wv->title || wv->call_data == 0)
 	{
 	  /* Only use MF_OWNERDRAW if GetMenuItemInfo is usable, since
 	     we can't deallocate the memory otherwise.  */
 	  if (get_menu_item_info)
 	    {
-	      out_string = LocalAlloc (LPTR, strlen (wv->name) + 1);
+	      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;
 	    }
@@ -2105,9 +2116,6 @@
 	fuFlags |= MF_UNCHECKED;
     }
 
-  if (item != NULL)
-    fuFlags = MF_POPUP;
-
   return_value =
     AppendMenu (menu,
                 fuFlags,
@@ -2124,15 +2132,11 @@
 	  info.cbSize = sizeof (info);
 	  info.fMask = MIIM_DATA;
 
-	  /* Set help string for menu item.  Allocate new memory
-	     from the heap for it, since garbage collection can
-	     occur while menus are active.  */
+	  /* Set help string for menu item.  Leave it as a Lisp_Object
+	     until it is ready to be displayed, since GC can happen while
+	     menus are active.  */
 	  if (wv->help)
-	    {
-	      info.dwItemData
-		= (DWORD) LocalAlloc (LPTR, strlen(wv->help) + 1);
-	      strcpy (info.dwItemData, wv->help);
-	    }
+	    info.dwItemData = (DWORD) wv->help;
 
 	  if (wv->button_type == BUTTON_TYPE_RADIO)
 	    {
@@ -2213,7 +2217,7 @@
 	  info.fMask = MIIM_DATA;
 	  get_menu_item_info (menu, item, FALSE, &info);
 
-	  help = info.dwItemData ? build_string ((char *)info.dwItemData) : Qnil;
+	  help = info.dwItemData ? (Lisp_Object) info.dwItemData : Qnil;
 	}
 
       /* Store the help echo in the keyboard buffer as the X toolkit
@@ -2232,7 +2236,7 @@
     }
 }
 
-/* Free memory used by owner-drawn and help_echo strings.  */
+/* Free memory used by owner-drawn strings.  */
 static void
 w32_free_submenu_strings (menu)
      HMENU menu;
@@ -2243,13 +2247,18 @@
       MENUITEMINFO info;
 
       info.cbSize = sizeof (info);
-      info.fMask = MIIM_DATA | MIIM_SUBMENU;
+      info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU;
 
       get_menu_item_info (menu, i, TRUE, &info);
 
-      /* Both owner-drawn names and help strings are held in dwItemData.  */
-      if (info.dwItemData)
-	LocalFree (info.dwItemData);
+      /* Owner-drawn names are held in dwItemData.  */
+      if ((info.fType & MF_OWNERDRAW) && info.dwItemData)
+	{
+#ifdef MENU_DEBUG
+	  DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData);
+#endif
+	  LocalFree (info.dwItemData);
+	}
 
       /* Recurse down submenus.  */
       if (info.hSubMenu)