Add the latest changes to etags behaviour.
[bpt/emacs.git] / src / w32menu.c
index 772749a..043e673 100644 (file)
@@ -24,11 +24,13 @@ Boston, MA 02111-1307, USA.  */
 #include <stdio.h>
 #include "lisp.h"
 #include "termhooks.h"
+#include "keyboard.h"
 #include "frame.h"
 #include "window.h"
-#include "keyboard.h"
 #include "blockinput.h"
 #include "buffer.h"
+#include "charset.h"
+#include "coding.h"
 
 /* This may include sys/types.h, and that somehow loses
    if this is not done before the other system files.  */
@@ -43,8 +45,7 @@ Boston, MA 02111-1307, USA.  */
 #include "dispextern.h"
 
 #undef HAVE_MULTILINGUAL_MENU
-#undef HAVE_BOXES /* NTEMACS_TODO: Fix native checkmarks and radios.  */
-#undef HAVE_DIALOGS /* NTEMACS_TODO: Fix native dialogs.  */
+#undef HAVE_DIALOGS /* TODO: Implement native dialogs.  */
 
 /******************************************************************/
 /* Definitions copied from lwlib.h */
@@ -52,19 +53,6 @@ Boston, MA 02111-1307, USA.  */
 typedef void * XtPointer;
 typedef char Boolean;
 
-#define True 1
-#define False 0
-
-#if 0 /* Not used below.  */
-typedef enum _change_type
-{
-  NO_CHANGE = 0,
-  INVISIBLE_CHANGE = 1,
-  VISIBLE_CHANGE = 2,
-  STRUCTURAL_CHANGE = 3
-} change_type;
-#endif
-
 enum button_type
 {
   BUTTON_TYPE_NONE,
@@ -408,7 +396,8 @@ keymap_panes (keymaps, nmaps, notreal)
      But don't make a pane that is empty--ignore that map instead.
      P is the number of panes we have made so far.  */
   for (mapno = 0; mapno < nmaps; mapno++)
-    single_keymap_panes (keymaps[mapno], Qnil, Qnil, notreal, 10);
+    single_keymap_panes (keymaps[mapno],
+                         map_prompt (keymaps[mapno]), Qnil, notreal, 10);
 
   finish_menu_items ();
 }
@@ -433,21 +422,12 @@ single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
   Lisp_Object pending_maps = Qnil;
   Lisp_Object tail, item;
   struct gcpro gcpro1, gcpro2;
-  int notbuttons = 0;
 
   if (maxdepth <= 0)
     return;
 
   push_menu_pane (pane_name, prefix);
 
-#ifndef HAVE_BOXES
-  /* Remember index for first item in this pane so we can go back and
-     add a prefix when (if) we see the first button.  After that, notbuttons
-     is set to 0, to mark that we have seen a button and all non button
-     items need a prefix.  */
-  notbuttons = menu_items_used;
-#endif
-
   for (tail = keymap; CONSP (tail); tail = XCDR (tail))
     {
       GCPRO2 (keymap, pending_maps);
@@ -456,7 +436,7 @@ single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
       item = XCAR (tail);
       if (CONSP (item))
        single_menu_item (XCAR (item), XCDR (item),
-                         &pending_maps, notreal, maxdepth, &notbuttons);
+                         &pending_maps, notreal, maxdepth);
       else if (VECTORP (item))
        {
          /* Loop over the char values represented in the vector.  */
@@ -467,7 +447,7 @@ single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
              Lisp_Object character;
              XSETFASTINT (character, c);
              single_menu_item (character, XVECTOR (item)->contents[c],
-                               &pending_maps, notreal, maxdepth, &notbuttons);
+                               &pending_maps, notreal, maxdepth);
            }
        }
       UNGCPRO;
@@ -495,18 +475,13 @@ single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
    separate panes.
    If NOTREAL is nonzero, only check for equivalent key bindings, don't
    evaluate expressions in menu items and don't make any menu.
-   If we encounter submenus deeper than MAXDEPTH levels, ignore them.
-   NOTBUTTONS_PTR is only used when simulating toggle boxes and radio
-   buttons.  It points to variable notbuttons in single_keymap_panes,
-   which keeps track of if we have seen a button in this menu or not.  */
+   If we encounter submenus deeper than MAXDEPTH levels, ignore them.  */
 
 static void
-single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth,
-                 notbuttons_ptr)
+single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth)
      Lisp_Object key, item;
      Lisp_Object *pending_maps_ptr;
      int maxdepth, notreal;
-     int *notbuttons_ptr;
 {
   Lisp_Object map, item_string, enabled;
   struct gcpro gcpro1, gcpro2;
@@ -542,75 +517,6 @@ single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth,
       return;
     }
 
-#ifndef HAVE_BOXES
-  /* Simulate radio buttons and toggle boxes by putting a prefix in
-     front of them.  */
-  {
-    Lisp_Object prefix = Qnil;
-    Lisp_Object type = XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE];
-    if (!NILP (type))
-      {
-       Lisp_Object selected
-         = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED];
-
-       if (*notbuttons_ptr)
-         /* The first button. Line up previous items in this menu.  */
-         {
-           int index = *notbuttons_ptr; /* Index for first item this menu.  */
-           int submenu = 0;
-           Lisp_Object tem;
-           while (index < menu_items_used)
-             {
-               tem
-                 = XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME];
-               if (NILP (tem))
-                 {
-                   index++;
-                   submenu++;          /* Skip sub menu.  */
-                 }
-               else if (EQ (tem, Qlambda))
-                 {
-                   index++;
-                   submenu--;          /* End sub menu.  */
-                 }
-               else if (EQ (tem, Qt))
-                 index += 3;           /* Skip new pane marker. */
-               else if (EQ (tem, Qquote))
-                 index++;              /* Skip a left, right divider. */
-               else
-                 {
-                   if (!submenu && XSTRING (tem)->data[0] != '\0'
-                       && XSTRING (tem)->data[0] != '-')
-                     XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME]
-                       = concat2 (build_string ("    "), tem);
-                   index += MENU_ITEMS_ITEM_LENGTH;
-                 }
-             }
-           *notbuttons_ptr = 0;
-         }
-
-       /* Calculate prefix, if any, for this item.  */
-       if (EQ (type, QCtoggle))
-         prefix = build_string (NILP (selected) ? "[ ] " : "[X] ");
-       else if (EQ (type, QCradio))
-         prefix = build_string (NILP (selected) ? "( ) " : "(*) ");
-      }
-    /* Not a button. If we have earlier buttons, then we need a prefix.  */
-    else if (!*notbuttons_ptr && XSTRING (item_string)->data[0] != '\0'
-            && XSTRING (item_string)->data[0] != '-')
-      prefix = build_string ("    ");
-
-    if (!NILP (prefix))
-      item_string = concat2 (prefix, item_string);
-  }
-#endif /* HAVE_BOXES */
-#if 0
-  if (!NILP(map))
-    /* Indicate visually that this is a submenu.  */
-    item_string = concat2 (item_string, build_string (" >"));
-#endif
-
   push_menu_item (item_string, enabled, key,
                  XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF],
                  XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ],
@@ -618,7 +524,6 @@ single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth,
                   XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
                   XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
 
-#if 1
   /* Display a submenu using the toolkit.  */
   if (! (NILP (map) || NILP (enabled)))
     {
@@ -626,7 +531,6 @@ single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth,
       single_keymap_panes (map, Qnil, key, 0, maxdepth - 1);
       push_submenu_end ();
     }
-#endif
 }
 \f
 /* Push all the panes and items of a menu described by the
@@ -735,7 +639,8 @@ cached information about equivalent key sequences.")
 
       /* Decode the first argument: find the window and the coordinates.  */
       if (EQ (position, Qt)
-         || (CONSP (position) && EQ (XCAR (position), Qmenu_bar)))
+         || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
+                                   || EQ (XCAR (position), Qtool_bar))))
        {
          /* Use the mouse's current position.  */
          FRAME_PTR new_f = SELECTED_FRAME ();
@@ -814,15 +719,11 @@ cached information about equivalent key sequences.")
 
   /* Decode the menu items from what was specified.  */
 
-  keymap = Fkeymapp (menu);
-  tem = Qnil;
-  if (CONSP (menu))
-    tem = Fkeymapp (Fcar (menu));
-  if (!NILP (keymap))
+  keymap = get_keymap (menu, 0, 0);
+  if (CONSP (keymap))
     {
       /* We were given a keymap.  Extract menu info from the keymap.  */
       Lisp_Object prompt;
-      keymap = get_keymap (menu);
 
       /* Extract the detailed info to make one pane.  */
       keymap_panes (&menu, 1, NILP (position));
@@ -839,7 +740,7 @@ cached information about equivalent key sequences.")
 
       keymaps = 1;
     }
-  else if (!NILP (tem))
+  else if (CONSP (menu) && KEYMAPP (XCAR (menu)))
     {
       /* We were given a list of keymaps.  */
       int nmaps = XFASTINT (Flength (menu));
@@ -855,7 +756,7 @@ cached information about equivalent key sequences.")
        {
          Lisp_Object prompt;
 
-         maps[i++] = keymap = get_keymap (Fcar (tem));
+         maps[i++] = keymap = get_keymap (Fcar (tem), 1, 0);
 
          prompt = map_prompt (keymap);
          if (NILP (title) && !NILP (prompt))
@@ -933,13 +834,14 @@ on the left of the dialog box and all following items on the right.\n\
 
   /* Decode the first argument: find the window or frame to use.  */
   if (EQ (position, Qt)
-      || (CONSP (position) && EQ (XCAR (position), Qmenu_bar)))
+      || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
+                               || EQ (XCAR (position), Qtool_bar))))
     {
 #if 0 /* Using the frame the mouse is on may not be right.  */
       /* Use the mouse's current position.  */
       FRAME_PTR new_f = SELECTED_FRAME ();
       Lisp_Object bar_window;
-      int part;
+      enum scroll_bar_part part;
       unsigned long time;
       Lisp_Object x, y;
 
@@ -1096,27 +998,31 @@ menubar_selection_callback (FRAME_PTR f, void * client_data)
              Lisp_Object frame;
 
              XSETFRAME (frame, f);
-             buf.kind = menu_bar_event;
-             buf.frame_or_window = Fcons (frame, Fcons (Qmenu_bar, Qnil));
+             buf.kind = MENU_BAR_EVENT;
+             buf.frame_or_window = frame;
+             buf.arg = frame;
              kbd_buffer_store_event (&buf);
 
              for (j = 0; j < submenu_depth; j++)
                if (!NILP (subprefix_stack[j]))
                  {
-                   buf.kind = menu_bar_event;
-                   buf.frame_or_window = Fcons (frame, subprefix_stack[j]);
+                   buf.kind = MENU_BAR_EVENT;
+                   buf.frame_or_window = frame;
+                   buf.arg = subprefix_stack[j];
                    kbd_buffer_store_event (&buf);
                  }
 
              if (!NILP (prefix))
                {
-                 buf.kind = menu_bar_event;
-                 buf.frame_or_window = Fcons (frame, prefix);
+                 buf.kind = MENU_BAR_EVENT;
+                 buf.frame_or_window = frame;
+                 buf.arg = prefix;
                  kbd_buffer_store_event (&buf);
                }
 
-             buf.kind = menu_bar_event;
-             buf.frame_or_window = Fcons (frame, entry);
+             buf.kind = MENU_BAR_EVENT;
+             buf.frame_or_window = frame;
+             buf.arg = entry;
              kbd_buffer_store_event (&buf);
 
              return;
@@ -1204,8 +1110,7 @@ single_submenu (item_key, item_name, maps)
   for (i = 0; i < len; i++)
     {
       if (SYMBOLP (mapvec[i])
-         || (CONSP (mapvec[i])
-             && NILP (Fkeymapp (mapvec[i]))))
+         || (CONSP (mapvec[i]) && !KEYMAPP (mapvec[i])))
        {
          /* Here we have a command at top level in the menu bar
             as opposed to a submenu.  */
@@ -1268,7 +1173,7 @@ single_submenu (item_key, item_name, maps)
          prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
 #ifndef HAVE_MULTILINGUAL_MENU
          if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
-           pane_name = string_make_unibyte (pane_name);
+           pane_name = ENCODE_SYSTEM (pane_name);
 #endif
          pane_string = (NILP (pane_name)
                         ? "" : (char *) XSTRING (pane_name)->data);
@@ -1317,9 +1222,9 @@ single_submenu (item_key, item_name, maps)
 
 #ifndef HAVE_MULTILINGUAL_MENU
          if (STRING_MULTIBYTE (item_name))
-           item_name = string_make_unibyte (item_name);
+           item_name = ENCODE_SYSTEM (item_name);
          if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
-           descrip = string_make_unibyte (descrip);
+           descrip = ENCODE_SYSTEM (descrip);
 #endif
 
          wv = xmalloc_widget_value ();
@@ -1348,8 +1253,10 @@ single_submenu (item_key, item_name, maps)
 
          wv->selected = !NILP (selected);
          if (STRINGP (help))
-           wv->help = XSTRING (help)->data;
-                  
+           wv->help = (char *) XSTRING (help)->data;
+          else
+            wv->help = NULL;
+
          prev_wv = wv;
 
          i += MENU_ITEMS_ITEM_LENGTH;
@@ -1434,7 +1341,7 @@ set_frame_menubar (f, first_time, deep_p)
       set_buffer_internal_1 (XBUFFER (buffer));
 
       /* Run the Lucid hook.  */
-      call1 (Vrun_hooks, Qactivate_menubar_hook);
+      safe_run_hooks (Qactivate_menubar_hook);
       /* If it has changed current-menubar from previous value,
         really recompute the menubar from the value.  */
       if (! NILP (Vlucid_menu_bar_dirty_flag))
@@ -1656,7 +1563,6 @@ w32_menu_show (f, x, y, for_click, keymaps, title, error)
     = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
   int submenu_depth = 0;
   int first_pane;
-  int next_release_must_exit = 0;
 
   *error = NULL;
 
@@ -1711,7 +1617,7 @@ w32_menu_show (f, x, y, for_click, keymaps, title, error)
          prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
 #ifndef HAVE_MULTILINGUAL_MENU
          if (!NILP (pane_name) && STRING_MULTIBYTE (pane_name))
-           pane_name = string_make_unibyte (pane_name);
+           pane_name = ENCODE_SYSTEM (pane_name);
 #endif
          pane_string = (NILP (pane_name)
                         ? "" : (char *) XSTRING (pane_name)->data);
@@ -1750,7 +1656,8 @@ w32_menu_show (f, x, y, for_click, keymaps, title, error)
       else
        {
          /* Create a new item within current pane.  */
-         Lisp_Object item_name, enable, descrip, def, type, selected;
+         Lisp_Object item_name, enable, descrip, def, type, selected, help;
+
          item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
          enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
          descrip
@@ -1758,12 +1665,13 @@ w32_menu_show (f, x, y, for_click, keymaps, title, error)
          def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION];
          type = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_TYPE];
          selected = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_SELECTED];
+          help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
 
 #ifndef HAVE_MULTILINGUAL_MENU
           if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
-            item_name = string_make_unibyte (item_name);
+            item_name = ENCODE_SYSTEM (item_name);
           if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
-            item_name = string_make_unibyte (descrip);
+            descrip = ENCODE_SYSTEM (descrip);
 #endif
 
          wv = xmalloc_widget_value ();
@@ -1790,7 +1698,12 @@ w32_menu_show (f, x, y, for_click, keymaps, title, error)
            abort ();
 
          wv->selected = !NILP (selected);
-         
+
+          if (STRINGP (help))
+            wv->help = (char *) XSTRING (help)->data;
+          else
+            wv->help = NULL;
+
          prev_wv = wv;
 
          i += MENU_ITEMS_ITEM_LENGTH;
@@ -1810,10 +1723,11 @@ w32_menu_show (f, x, y, for_click, keymaps, title, error)
 
 #ifndef HAVE_MULTILINGUAL_MENU
       if (STRING_MULTIBYTE (title))
-       title = string_make_unibyte (title);
+       title = ENCODE_SYSTEM (title);
 #endif
       wv_title->name = (char *) XSTRING (title)->data;
-      wv_title->enabled = True;
+      wv_title->enabled = TRUE;
+      wv_title->title = TRUE;
       wv_title->button_type = BUTTON_TYPE_NONE;
       wv_title->next = wv_sep;
       first_wv->contents = wv_title;
@@ -1828,9 +1742,6 @@ w32_menu_show (f, x, y, for_click, keymaps, title, error)
   pos.y = y;
   ClientToScreen (FRAME_W32_WINDOW (f), &pos);
 
-  /* Free the widget_value objects we used to specify the contents.  */
-  free_menubar_widget_value_tree (first_wv);
-
   /* No selection has been chosen yet.  */
   menu_item_selection = 0;
 
@@ -1843,6 +1754,9 @@ w32_menu_show (f, x, y, for_click, keymaps, title, error)
      during the call. */
   discard_mouse_events ();
 
+  /* Free the widget_value objects we used to specify the contents.  */
+  free_menubar_widget_value_tree (first_wv);
+
   DestroyMenu (menu);
 
   /* Find the selected item, and its pane, to return
@@ -1957,11 +1871,13 @@ w32_dialog_show (f, keymaps, title, error)
       {
        
        /* Create a new item within current pane.  */
-       Lisp_Object item_name, enable, descrip;
+       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))
          {
@@ -2030,7 +1946,7 @@ w32_dialog_show (f, keymaps, title, error)
   menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
                           f->output_data.w32->widget, 1, 0,
                           dialog_selection_callback, 0);
-  lw_modify_all_widgets (dialog_id, first_wv->contents, True);
+  lw_modify_all_widgets (dialog_id, first_wv->contents, TRUE);
 #endif
 
   /* Free the widget_value objects we used to specify the contents.  */
@@ -2114,9 +2030,13 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item)
 {
   UINT fuFlags;
   char *out_string;
+  int return_value;
 
   if (name_is_separator (wv->name))
-    fuFlags = MF_SEPARATOR;
+    {
+      fuFlags = MF_SEPARATOR;
+      out_string = NULL;
+    }
   else 
     {
       if (wv->enabled)
@@ -2142,60 +2062,59 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item)
 #endif
          fuFlags = MF_OWNERDRAW | MF_DISABLED;
        }
-
-#ifdef HAVE_BOXES
       /* Draw radio buttons and tickboxes. */
-      {
-      switch (wv->button_type)
-        {
-        case BUTTON_TYPE_TOGGLE:
-          CheckMenuItem (menu, (UINT)item,
-                         wv->selected ? MF_CHECKED : MF_UNCHECKED);
-          break;
-
-        case BUTTON_TYPE_RADIO:
-          /* CheckMenuRadioItem does not exist on NT 3.51 and
-             earlier. Fallback on CheckMenuItem.  */
-          {
-            HMODULE user32 = GetModuleHandle ("user32.dll");
-            FARPROC set_menu_item_info
-              = GetProcAddress (user32, "SetMenuItemInfo");
-            if (set_menu_item_info)
-              {
-                MENUITEMINFO info;
-                bzero (&info, sizeof (info));
-                info.cbSize = sizeof (info);
-                info.fMask = MIIM_TYPE | MIIM_STATE;
-                info.fType = MFT_RADIOCHECK;
-                info.fState = wv->selected ? MFS_CHECKED : MFS_UNCHECKED;
-                
-                set_menu_item_info (menu, item, FALSE, &info);
-              }
-            else
-              CheckMenuItem (menu, (UINT)item, wv->selected ?
-                             MF_CHECKED : MF_UNCHECKED);
-          }
-          break;
-
-        default:
-          CheckMenuItem (menu, (UINT)item, MF_UNCHECKED);
-          break;
-        }
-      }
-#endif
+      else if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
+                           wv->button_type == BUTTON_TYPE_RADIO))
+       fuFlags |= MF_CHECKED;
+      else
+       fuFlags |= MF_UNCHECKED;
     }
 
   if (item != NULL)
     fuFlags = MF_POPUP;
 
-  return AppendMenu (menu,
-                    fuFlags,
-                    item != NULL ? (UINT) item : (UINT) wv->call_data,
-                    (fuFlags == MF_SEPARATOR) ? NULL: out_string );
+  return_value =
+    AppendMenu (menu,
+                fuFlags,
+                item != NULL ? (UINT) item : (UINT) wv->call_data,
+                out_string );
+
+  /* This must be done after the menu item is created.  */
+  if ((fuFlags & MF_STRING) != 0)
+    {
+      HMODULE user32 = GetModuleHandle ("user32.dll");
+      FARPROC set_menu_item_info = GetProcAddress (user32, "SetMenuItemInfoA");
+
+      if (set_menu_item_info)
+       {
+         MENUITEMINFO info;
+         bzero (&info, sizeof (info));
+         info.cbSize = sizeof (info);
+         info.fMask = MIIM_DATA;
+
+         /* Set help string for menu item.  */
+         info.dwItemData = (DWORD)wv->help;
+
+         if (wv->button_type == BUTTON_TYPE_RADIO)
+           {
+             /* CheckMenuRadioItem allows us to differentiate TOGGLE and
+                RADIO items, but is not available on NT 3.51 and earlier.  */
+             info.fMask |= MIIM_TYPE | MIIM_STATE;
+             info.fType = MFT_RADIOCHECK | MFT_STRING;
+             info.dwTypeData = out_string;
+             info.fState = wv->selected ? MFS_CHECKED : MFS_UNCHECKED;
+           }
+
+         set_menu_item_info (menu,
+                             item != NULL ? (UINT) item : (UINT) wv->call_data,
+                             FALSE, &info);
+       }
+    }
+  return return_value;
 }
 
 /* Construct native Windows menu(bar) based on widget_value tree.  */
-static int
+int
 fill_in_menu (HMENU menu, widget_value *wv)
 {
   int items_added = 0;
@@ -2232,6 +2151,52 @@ popup_activated ()
   return 0;
 }
 
+/* Display help string for currently pointed to menu item. Not
+   supported on NT 3.51 and earlier, as GetMenuItemInfo is not
+   available. */
+void
+w32_menu_display_help (HMENU menu, UINT item, UINT flags)
+{
+  int pane = 0; /* TODO: Set this to pane number.  */
+
+  HMODULE user32 = GetModuleHandle ("user32.dll");
+  FARPROC get_menu_item_info = GetProcAddress (user32, "GetMenuItemInfoA");
+
+  if (get_menu_item_info)
+    {
+      extern Lisp_Object Qmenu_item;
+      Lisp_Object *first_item;
+      Lisp_Object pane_name;
+      Lisp_Object menu_object;
+      MENUITEMINFO info;
+
+      bzero (&info, sizeof (info));
+      info.cbSize = sizeof (info);
+      info.fMask = MIIM_DATA;
+      get_menu_item_info (menu, item, FALSE, &info);
+
+      first_item = XVECTOR (menu_items)->contents;
+      if (EQ (first_item[0], Qt))
+        pane_name = first_item[MENU_ITEMS_PANE_NAME];
+      else if (EQ (first_item[0], Qquote))
+        /* This shouldn't happen, see w32_menu_show.  */
+        pane_name = build_string ("");
+      else
+        pane_name = first_item[MENU_ITEMS_ITEM_NAME];
+
+      /* (menu-item MENU-NAME PANE-NUMBER)  */
+      menu_object = Fcons (Qmenu_item,
+                           Fcons (pane_name,
+                                  Fcons (make_number (pane), Qnil)));
+
+      show_help_echo (info.dwItemData ?
+                     build_string ((char *) info.dwItemData) : Qnil,
+                      Qnil, menu_object, make_number (item), 1);
+    }
+}
+
+
+
 #endif /* HAVE_MENUS */
 \f
 syms_of_w32menu ()