changeset 27400:da3ee40952bf

Add skeleton support for help strings on menus. (add_menu_item): Native checkbox and radio support added, but not yet enabled due to bugs. (push_menu_item): Add parameters type, selection and help. Callers updated. Formatting changes to reduce unnecessary diffs with xmenu.c.
author Jason Rumney <jasonr@gnu.org>
date Sun, 23 Jan 2000 03:22:21 +0000
parents 22e4449438ff
children 8c35aee5448d
files src/w32menu.c
diffstat 1 files changed, 199 insertions(+), 78 deletions(-) [+]
line wrap: on
line diff
--- a/src/w32menu.c	Sun Jan 23 03:21:01 2000 +0000
+++ b/src/w32menu.c	Sun Jan 23 03:22:21 2000 +0000
@@ -20,6 +20,7 @@
 
 #include <config.h>
 #include <signal.h>
+
 #include <stdio.h>
 #include "lisp.h"
 #include "termhooks.h"
@@ -41,6 +42,10 @@
 
 #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.  */
+
 /******************************************************************/
 /* Definitions copied from lwlib.h */
 
@@ -50,6 +55,7 @@
 #define True 1
 #define False 0
 
+#if 0 /* Not used below.  */
 typedef enum _change_type
 {
   NO_CHANGE = 0,
@@ -57,6 +63,14 @@
   VISIBLE_CHANGE = 2,
   STRUCTURAL_CHANGE = 3
 } change_type;
+#endif
+
+enum button_type
+{
+  BUTTON_TYPE_NONE,
+  BUTTON_TYPE_TOGGLE,
+  BUTTON_TYPE_RADIO
+};
 
 typedef struct _widget_value
 {
@@ -66,10 +80,14 @@
   char*		value;
   /* keyboard equivalent. no implications for XtTranslations */ 
   char*		key;
+  /* Help string or null if none.  */
+  char		*help;
   /* true if enabled */
   Boolean	enabled;
   /* true if selected */
   Boolean	selected;
+  /* The type of a button.  */
+  enum button_type button_type;
   /* true if menu title */
   Boolean       title;
 #if 0
@@ -133,8 +151,11 @@
 
 void set_frame_menubar ();
 
+static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
+				Lisp_Object, Lisp_Object, Lisp_Object,
+				Lisp_Object, Lisp_Object));
+static Lisp_Object w32_dialog_show ();
 static Lisp_Object w32_menu_show ();
-static Lisp_Object w32_dialog_show ();
 
 static void keymap_panes ();
 static void single_keymap_panes ();
@@ -168,12 +189,18 @@
 #define MENU_ITEMS_PANE_PREFIX 2
 #define MENU_ITEMS_PANE_LENGTH 3
 
-#define MENU_ITEMS_ITEM_NAME 0
-#define MENU_ITEMS_ITEM_ENABLE 1
-#define MENU_ITEMS_ITEM_VALUE 2
-#define MENU_ITEMS_ITEM_EQUIV_KEY 3
-#define MENU_ITEMS_ITEM_DEFINITION 4
-#define MENU_ITEMS_ITEM_LENGTH 5
+enum menu_item_idx
+{
+  MENU_ITEMS_ITEM_NAME = 0,
+  MENU_ITEMS_ITEM_ENABLE,
+  MENU_ITEMS_ITEM_VALUE,
+  MENU_ITEMS_ITEM_EQUIV_KEY,
+  MENU_ITEMS_ITEM_DEFINITION,
+  MENU_ITEMS_ITEM_TYPE,
+  MENU_ITEMS_ITEM_SELECTED,
+  MENU_ITEMS_ITEM_HELP,
+  MENU_ITEMS_ITEM_LENGTH
+};
 
 static Lisp_Object menu_items;
 
@@ -194,6 +221,8 @@
    Xt on behalf of one of the widget sets.  */
 static int popup_activated_flag;
 
+static int next_menubar_widget_id;
+
 /* This is set nonzero after the user activates the menu bar, and set
    to zero again after the menu bars are redisplayed by prepare_menu_bar.
    While it is nonzero, all calls to set_frame_menubar go deep.
@@ -205,10 +234,11 @@
 
 
 /* Return the frame whose ->output_data.w32->menubar_widget equals
-   MENU, or 0 if none.  */
+   ID, or 0 if none.  */
 
 static struct frame *
-menubar_id_to_frame (HMENU menu)
+menubar_id_to_frame (id)
+     HMENU id;
 {
   Lisp_Object tail, frame;
   FRAME_PTR f;
@@ -219,9 +249,9 @@
       if (!GC_FRAMEP (frame))
         continue;
       f = XFRAME (frame);
-      if (!FRAME_W32_P (f))
+      if (!FRAME_WINDOW_P (f))
 	continue;
-      if (f->output_data.w32->menubar_widget == menu)
+      if (f->output_data.w32->menubar_widget == id)
 	return f;
     }
   return 0;
@@ -334,17 +364,17 @@
   XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
 }
 
-/* Push one menu item into the current pane.
-   NAME is the string to display.  ENABLE if non-nil means
-   this item can be selected.  KEY is the key generated by
-   choosing this item, or nil if this item doesn't really have a definition.
-   DEF is the definition of this item.
-   EQUIV is the textual description of the keyboard equivalent for
-   this item (or nil if none).  */
+/* Push one menu item into the current pane.  NAME is the string to
+   display.  ENABLE if non-nil means this item can be selected.  KEY
+   is the key generated by choosing this item, or nil if this item
+   doesn't really have a definition.  DEF is the definition of this
+   item.  EQUIV is the textual description of the keyboard equivalent
+   for this item (or nil if none).  TYPE is the type of this menu
+   item, one of nil, `toggle' or `radio'. */
 
 static void
-push_menu_item (name, enable, key, def, equiv)
-     Lisp_Object name, enable, key, def, equiv;
+push_menu_item (name, enable, key, def, equiv, type, selected, help)
+     Lisp_Object name, enable, key, def, equiv, type, selected, help;
 {
   if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
     grow_menu_items ();
@@ -354,6 +384,9 @@
   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,
@@ -475,7 +508,7 @@
      int maxdepth, notreal;
      int *notbuttons_ptr;
 {
-  Lisp_Object def, map, item_string, enabled;
+  Lisp_Object map, item_string, enabled;
   struct gcpro gcpro1, gcpro2;
   int res;
   
@@ -570,7 +603,7 @@
     if (!NILP (prefix))
       item_string = concat2 (prefix, item_string);
   }
-#endif /* not HAVE_BOXES */
+#endif /* HAVE_BOXES */
  
 #if 0
   if (!NILP(map))
@@ -580,7 +613,10 @@
 
   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_KEYEQ],
+		  XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE],
+                  XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
+                  XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
 
 #if 1
   /* Display a submenu using the toolkit.  */
@@ -632,7 +668,7 @@
     {
       item = Fcar (tail);
       if (STRINGP (item))
-	push_menu_item (item, Qnil, Qnil, Qt, Qnil);
+	push_menu_item (item, Qnil, Qnil, Qt, Qnil, Qnil, Qnil, Qnil);
       else if (NILP (item))
 	push_left_right_boundary ();
       else
@@ -640,7 +676,7 @@
 	  CHECK_CONS (item, 0);
 	  item1 = Fcar (item);
 	  CHECK_STRING (item1, 1);
-	  push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil);
+	  push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil, Qnil, Qnil, Qnil);
 	}
     }
 }
@@ -681,13 +717,11 @@
   (position, menu)
      Lisp_Object position, menu;
 {
-  int number_of_panes, panes;
   Lisp_Object keymap, tem;
   int xpos, ypos;
   Lisp_Object title;
   char *error_name;
   Lisp_Object selection;
-  int i, j;
   FRAME_PTR f;
   Lisp_Object x, y, window;
   int keymaps = 0;
@@ -704,9 +738,9 @@
 	  || (CONSP (position) && EQ (XCAR (position), Qmenu_bar)))
 	{
 	  /* Use the mouse's current position.  */
-	  FRAME_PTR new_f = selected_frame;
+	  FRAME_PTR new_f = SELECTED_FRAME ();
 	  Lisp_Object bar_window;
-	  int part;
+	  enum scroll_bar_part part;
 	  unsigned long time;
 
 	  if (mouse_position_hook)
@@ -757,9 +791,9 @@
 	  CHECK_LIVE_WINDOW (window, 0);
 	  f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
 
-	  xpos = (FONT_WIDTH (f->output_data.w32->font)
+	  xpos = (FONT_WIDTH (FRAME_FONT (f))
 		  * XFASTINT (XWINDOW (window)->left));
-	  ypos = (f->output_data.w32->line_height
+	  ypos = (FRAME_LINE_HEIGHT (f)
 		  * XFASTINT (XWINDOW (window)->top));
 	}
       else
@@ -903,7 +937,7 @@
     {
 #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;
+      FRAME_PTR new_f = SELECTED_FRAME ();
       Lisp_Object bar_window;
       int part;
       unsigned long time;
@@ -949,7 +983,7 @@
        but I don't want to make one now.  */
     CHECK_WINDOW (window, 0);
 
-#if 1
+#ifndef HAVE_DIALOGS
   /* Display a menu with these alternatives
      in the middle of frame F.  */
   {
@@ -962,7 +996,7 @@
     return Fx_popup_menu (newpos,
 			  Fcons (Fcar (contents), Fcons (contents, Qnil)));
   }
-#else
+#else /* HAVE_DIALOGS */
   {
     Lisp_Object title;
     char *error_name;
@@ -984,7 +1018,7 @@
     if (error_name) error (error_name);
     return selection;
   }
-#endif
+#endif /* HAVE_DIALOGS */
 }
 
 /* Activate the menu bar of frame F.
@@ -999,6 +1033,7 @@
 
    This way we can safely execute Lisp code.  */
    
+void
 x_activate_menubar (f)
      FRAME_PTR f;
 {
@@ -1148,7 +1183,6 @@
   int len;
   Lisp_Object *mapvec;
   widget_value **submenu_stack;
-  int mapno;
   int previous_items = menu_items_used;
   int top_level_items = 0;
 
@@ -1177,7 +1211,8 @@
 	     as opposed to a submenu.  */
 	  top_level_items = 1;
 	  push_menu_pane (Qnil, Qnil);
-	  push_menu_item (item_name, Qt, item_key, mapvec[i], Qnil);
+	  push_menu_item (item_name, Qt, item_key, mapvec[i],
+                          Qnil, Qnil, Qnil, Qnil);
 	}
       else
 	single_keymap_panes (mapvec[i], item_name, item_key, 0, 10);
@@ -1192,6 +1227,7 @@
   wv->name = "menu";
   wv->value = 0;
   wv->enabled = 1;
+  wv->button_type = BUTTON_TYPE_NONE;
   first_wv = wv;
   save_wv = 0;
   prev_wv = 0;
@@ -1230,6 +1266,10 @@
 	  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 = string_make_unibyte (pane_name);
+#endif
 	  pane_string = (NILP (pane_name)
 			 ? "" : (char *) XSTRING (pane_name)->data);
 	  /* If there is just one top-level pane, put all its items directly
@@ -1254,6 +1294,7 @@
 		wv->name++;
 	      wv->value = 0;
 	      wv->enabled = 1;
+	      wv->button_type = BUTTON_TYPE_NONE;
 	    }
 	  save_wv = wv;
 	  prev_wv = 0;
@@ -1262,12 +1303,24 @@
       else
 	{
 	  /* Create a new item within current pane.  */
-	  Lisp_Object item_name, enable, descrip, def;
+	  Lisp_Object item_name, enable, descrip, def, type, selected;
+          Lisp_Object 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];
 	  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 (STRING_MULTIBYTE (item_name))
+	    item_name = string_make_unibyte (item_name);
+	  if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
+	    descrip = string_make_unibyte (descrip);
+#endif
 
 	  wv = xmalloc_widget_value ();
 	  if (prev_wv) 
@@ -1283,6 +1336,20 @@
 	     as long as pointers have enough bits to hold small integers.  */
 	  wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0);
 	  wv->enabled = !NILP (enable);
+
+	  if (NILP (type))
+	    wv->button_type = BUTTON_TYPE_NONE;
+	  else if (EQ (type, QCradio))
+	    wv->button_type = BUTTON_TYPE_RADIO;
+	  else if (EQ (type, QCtoggle))
+	    wv->button_type = BUTTON_TYPE_TOGGLE;
+	  else
+	    abort ();
+
+	  wv->selected = !NILP (selected);
+	  if (STRINGP (help))
+	    wv->help = XSTRING (help)->data;
+		   
 	  prev_wv = wv;
 
 	  i += MENU_ITEMS_ITEM_LENGTH;
@@ -1312,7 +1379,7 @@
      int deep_p;
 {
   HMENU menubar_widget = f->output_data.w32->menubar_widget;
-  Lisp_Object tail, items, frame;
+  Lisp_Object items;
   widget_value *wv, *first_wv, *prev_wv = 0;
   int i;
 
@@ -1331,6 +1398,7 @@
   wv->name = "menubar";
   wv->value = 0;
   wv->enabled = 1;
+  wv->button_type = BUTTON_TYPE_NONE;
   first_wv = wv;
 
   if (deep_p)
@@ -1403,6 +1471,7 @@
 	    first_wv->contents = wv;
 	  /* Don't set wv->name here; GC during the loop might relocate it.  */
 	  wv->enabled = 1;
+	  wv->button_type = BUTTON_TYPE_NONE;
 	  prev_wv = wv;
 	}
 
@@ -1446,30 +1515,9 @@
   else
     {
       /* Make a widget-value tree containing
-	 just the top level menu bar strings.
-
-	 It turns out to be worth comparing the new contents with the
-	 previous contents to avoid unnecessary rebuilding even of just
-	 the top-level menu bar, which turns out to be fairly slow.  We
-	 co-opt f->menu_bar_vector for this purpose, since its contents
-	 are effectively discarded at this point anyway.
-
-	 Note that the lisp-level hooks have already been run by
-	 update_menu_bar - it's kinda a shame the code is duplicated
-	 above as well for deep_p, but there we are.  */
+	 just the top level menu bar strings.  */
 
       items = FRAME_MENU_BAR_ITEMS (f);
-
-      /* If there has been no change in the Lisp-level contents of just
-	 the menu bar itself, skip redisplaying it.  Just exit.  */
-      for (i = 0; i < f->menu_bar_items_used; i += 4)
-	if (i == XVECTOR (items)->size
-	    || (XVECTOR (f->menu_bar_vector)->contents[i]
-		!= XVECTOR (items)->contents[i]))
-	  break;
-      if (i == XVECTOR (items)->size && i == f->menu_bar_items_used && i != 0)
-	  return;
-
       for (i = 0; i < XVECTOR (items)->size; i += 4)
 	{
 	  Lisp_Object string;
@@ -1482,6 +1530,7 @@
 	  wv->name = (char *) XSTRING (string)->data;
 	  wv->value = 0;
 	  wv->enabled = 1;
+	  wv->button_type = BUTTON_TYPE_NONE;
 	  /* This prevents lwlib from assuming this
 	     menu item is really supposed to be empty.  */
 	  /* The EMACS_INT cast avoids a warning.
@@ -1495,16 +1544,10 @@
 	  prev_wv = wv;
 	}
 
-      /* Remember the contents of FRAME_MENU_BAR_ITEMS (f) in
-	 f->menu_bar_vector, so we can check whether the top-level
-	 menubar contents have changed next time.  */
-      if (XVECTOR (f->menu_bar_vector)->size < XVECTOR (items)->size)
-	f->menu_bar_vector
-	  = Fmake_vector (make_number (XVECTOR (items)->size), Qnil);
-      bcopy (XVECTOR (items)->contents,
-	     XVECTOR (f->menu_bar_vector)->contents,
-	     XVECTOR (items)->size * sizeof (Lisp_Object));
-      f->menu_bar_items_used = XVECTOR (items)->size;
+      /* Forget what we thought we knew about what is in the
+	 detailed contents of the menu bar menus.
+	 Changing the top level always destroys the contents.  */
+      f->menu_bar_items_used = 0;
     }
 
   /* Create or update the menu bar widget.  */
@@ -1612,7 +1655,6 @@
   Lisp_Object *subprefix_stack
     = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
   int submenu_depth = 0;
-
   int first_pane;
   int next_release_must_exit = 0;
 
@@ -1630,6 +1672,7 @@
   wv->name = "menu";
   wv->value = 0;
   wv->enabled = 1;
+  wv->button_type = BUTTON_TYPE_NONE;
   first_wv = wv;
   first_pane = 1;
  
@@ -1666,6 +1709,10 @@
 	  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 (!NILP (pane_name) && STRING_MULTIBYTE (pane_name))
+	    pane_name = string_make_unibyte (pane_name);
+#endif
 	  pane_string = (NILP (pane_name)
 			 ? "" : (char *) XSTRING (pane_name)->data);
 	  /* If there is just one top-level pane, put all its items directly
@@ -1688,6 +1735,7 @@
 		wv->name++;
 	      wv->value = 0;
 	      wv->enabled = 1;
+	      wv->button_type = BUTTON_TYPE_NONE;
 	      save_wv = wv;
 	      prev_wv = 0;
 	    }
@@ -1702,12 +1750,21 @@
       else
 	{
 	  /* Create a new item within current pane.  */
-	  Lisp_Object item_name, enable, descrip, def;
+	  Lisp_Object item_name, enable, descrip, def, type, selected;
 	  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];
 	  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];
+
+#ifndef HAVE_MULTILINGUAL_MENU
+          if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
+            item_name = string_make_unibyte (item_name);
+          if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
+            item_name = string_make_unibyte (descrip);
+#endif
 
 	  wv = xmalloc_widget_value ();
 	  if (prev_wv) 
@@ -1722,6 +1779,18 @@
              restricted to 16-bits..  */
 	  wv->call_data = !NILP (def) ? (void *) (EMACS_INT) i : 0;
 	  wv->enabled = !NILP (enable);
+
+	  if (NILP (type))
+	    wv->button_type = BUTTON_TYPE_NONE;
+	  else if (EQ (type, QCtoggle))
+	    wv->button_type = BUTTON_TYPE_TOGGLE;
+	  else if (EQ (type, QCradio))
+	    wv->button_type = BUTTON_TYPE_RADIO;
+	  else
+	    abort ();
+
+	  wv->selected = !NILP (selected);
+	  
 	  prev_wv = wv;
 
 	  i += MENU_ITEMS_ITEM_LENGTH;
@@ -1739,9 +1808,13 @@
       wv_sep->name = "--";
       wv_sep->next = first_wv->contents;
 
+#ifndef HAVE_MULTILINGUAL_MENU
+      if (STRING_MULTIBYTE (title))
+	title = string_make_unibyte (title);
+#endif
       wv_title->name = (char *) XSTRING (title)->data;
-      /* Handle title specially, so it looks better.  */
-      wv_title->title = True;
+      wv_title->enabled = True;
+      wv_title->button_type = BUTTON_TYPE_NONE;
       wv_title->next = wv_sep;
       first_wv->contents = wv_title;
     }
@@ -1749,7 +1822,7 @@
   /* Actually create the menu.  */
   menu = CreatePopupMenu ();
   fill_in_menu (menu, first_wv->contents);
-    
+
   /* Adjust coordinates to be root-window-relative.  */
   pos.x = x;
   pos.y = y;
@@ -1952,7 +2025,7 @@
   }
 
   /* Actually create the dialog.  */
-#if 0
+#ifdef HAVE_DIALOGS
   dialog_id = widget_id_tick++;
   menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
 			   f->output_data.w32->widget, 1, 0,
@@ -1967,7 +2040,7 @@
   menu_item_selection = 0;
 
   /* Display the menu.  */
-#if 0
+#ifdef HAVE_DIALOGS
   lw_pop_up_all_widgets (dialog_id);
   popup_activated_flag = 1;
 
@@ -2069,6 +2142,47 @@
 #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
     }
 
   if (item != NULL)
@@ -2111,6 +2225,13 @@
   return 1;
 }
 
+int
+popup_activated ()
+{
+  /* popup_activated_flag not actually used on W32 */
+  return 0;
+}
+
 #endif /* HAVE_MENUS */
 
 syms_of_w32menu ()