update.
[chise/xemacs-chise.git.1] / src / menubar-msw.c
index 33f456a..2cd701d 100644 (file)
@@ -116,31 +116,42 @@ static Lisp_Object current_hash_table;
 #define MENU_ITEM_ID_BITS(x) (((x) & 0x7FFF) | 0x8000)
 static HMENU top_level_menu;
 
-/* Translate (in place) %_ to &, %% to %.
-   Return new length, and (through accel) the accelerator character.
-   (If there is no accelerator, it will be added on the first character.)
-   len = number of bytes (not including zero terminator).
-   maxlen = size of buffer.
-   We assume and maintain zero-termination.  To be absolutely sure
-   of not hitting an error, maxlen should be >= 2*len + 3. */
-
+/*
+ * Translate (in place) X accelerator syntax to win32 accelerator syntax.
+ * Return new length.
+ * len = number of bytes (not including zero terminator).
+ * maxlen = size of buffer.
+ * accel = (Emchar*) to receive the accelerator character
+ *         or NULL to suppress accelerators in the menu or dialog item.
+ *
+ * %% is replaced with %
+ * if accel is NULL:
+ *   %_ is removed.
+ * if accel is non-NULL:
+ *   %_ is replaced with &.
+ *   The accelerator character is passed back in *accel.
+ *   (If there is no accelerator, it will be added on the first character.)
+ *
+ * We assume and maintain zero-termination.  To be absolutely sure
+ * of not hitting an error, maxlen should be >= 2*len + 3.
+ */
 Bytecount
 mswindows_translate_menu_or_dialog_item (Bufbyte *item, Bytecount len,
-                                  Bytecount maxlen, Emchar *accel,
-                                  Lisp_Object error_name)
+                                        Bytecount maxlen, Emchar *accel,
+                                        Lisp_Object error_name)
 {
   Bufbyte *ptr;
 
-  *accel = '\0';
+  if (accel)
+    *accel = '\0';
 
   /* Escape '&' as '&&' */
-  
   ptr = item;
   while ((ptr = (Bufbyte *) memchr (ptr, '&', len - (ptr - item))) != NULL)
     {
       if (len + 2 > maxlen)
-       signal_simple_error ("Menu item produces too long displayable string",
-                            error_name);
+       syntax_error ("Menu item produces too long displayable string",
+                     error_name);
       memmove (ptr + 1, ptr, (len - (ptr - item)) + 1);
       len++;
       ptr += 2;
@@ -153,27 +164,38 @@ mswindows_translate_menu_or_dialog_item (Bufbyte *item, Bytecount len,
     {
       if (*(ptr + 1) == '_')
        {
-         *ptr = '&';
-         if (!*accel)
-           /* #### urk !  We need a reference translation table for
-              case changes that aren't buffer-specific. */
-           *accel = DOWNCASE (current_buffer, charptr_emchar (ptr + 2));
-         memmove (ptr + 1, ptr + 2, len - (ptr - item + 2) + 1);
-         len--;
+         if (accel)
+           {
+             *ptr = '&';
+             if (!*accel)
+               /* #### urk !  We need a reference translation table for
+                  case changes that aren't buffer-specific. */
+               *accel = DOWNCASE (current_buffer, charptr_emchar (ptr + 2));
+             memmove (ptr + 1, ptr + 2, len - (ptr - item + 2) + 1);
+             len--;
+           }
+         else  /* Skip accelerator */
+           {
+             memmove (ptr, ptr + 2, len - (ptr - item + 2) + 1);
+             len-=2;
+           }
        }
       else if (*(ptr + 1) == '%')
        {
          memmove (ptr + 1, ptr + 2, len - (ptr - item + 2) + 1);
          len--;
+         ptr++;
        }
-      ptr++;
+      else     /* % on its own - shouldn't happen */
+       ptr++;
     }
 
-  if (!*accel)
+  if (accel && !*accel)
     {
+      /* Force a default accelerator */
       if (len + 2 > maxlen)
-       signal_simple_error ("Menu item produces too long displayable string",
-                            error_name);
+       syntax_error ("Menu item produces too long displayable string",
+                     error_name);
       ptr = item;
       memmove (ptr + 1, ptr, len + 1);
       /* #### urk !  We need a reference translation table for
@@ -202,7 +224,7 @@ displayable_menu_item (Lisp_Object gui_item, int bar_p, Emchar *accel)
   /* We construct the name in a static buffer. That's fine, because
      menu items longer than 128 chars are probably programming errors,
      and better be caught than displayed! */
-  
+
   static char buf[MAX_MENUITEM_LENGTH+2];
 
   /* Left flush part of the string */
@@ -298,7 +320,7 @@ checksum_menu_item (Lisp_Object item)
       return HASH2 (internal_hash (XVECTOR_DATA(item)[0], 0),
                    internal_hash (XVECTOR_DATA(item)[1], 0));
     }
+
   /* An error - will be caught later */
   return 0;
 }
@@ -310,6 +332,9 @@ populate_menu_add_item (HMENU menu, Lisp_Object path,
                        int flush_right, int bar_p)
 {
   MENUITEMINFO item_info;
+  UINT oldflags = MF_BYPOSITION;
+  UINT olduidnewitem = 0;
+  LPCTSTR oldlpnewitem = 0;
 
   item_info.cbSize = sizeof (item_info);
   item_info.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID;
@@ -321,12 +346,17 @@ populate_menu_add_item (HMENU menu, Lisp_Object path,
     {
       /* Separator or unselectable text */
       if (separator_string_p (XSTRING_DATA (item)))
-       item_info.fType = MFT_SEPARATOR;
+       {
+         item_info.fType = MFT_SEPARATOR;
+         oldflags |= MF_SEPARATOR;
+       }
       else
        {
          item_info.fType = MFT_STRING;
          item_info.fState = MFS_DISABLED;
          item_info.dwTypeData = XSTRING_DATA (item);
+         oldflags |= MF_STRING | MF_DISABLED;
+         oldlpnewitem = item_info.dwTypeData;
        }
     }
   else if (CONSP (item))
@@ -343,17 +373,20 @@ populate_menu_add_item (HMENU menu, Lisp_Object path,
       menu_parse_submenu_keywords (item, gui_item);
 
       if (!STRINGP (pgui_item->name))
-       signal_simple_error ("Menu name (first element) must be a string",
+       syntax_error ("Menu name (first element) must be a string",
                             item);
 
       if (!gui_item_included_p (gui_item, Vmenubar_configuration))
-      {
-       UNGCPRO;
-       goto done;
-      }
+       {
+         UNGCPRO;
+         goto done;
+       }
 
       if (!gui_item_active_p (gui_item))
-       item_info.fState = MFS_GRAYED;
+       {
+         item_info.fState = MFS_GRAYED;
+         oldflags |= MF_GRAYED;
+       }
       /* Temptation is to put 'else' right here. Although, the
         displayed item won't have an arrow indicating that it is a
         popup.  So we go ahead a little bit more and create a popup */
@@ -362,6 +395,9 @@ populate_menu_add_item (HMENU menu, Lisp_Object path,
       item_info.fMask |= MIIM_SUBMENU;
       item_info.dwTypeData = displayable_menu_item (gui_item, bar_p, &accel);
       item_info.hSubMenu = submenu;
+      olduidnewitem = (UINT) submenu;
+      oldlpnewitem = item_info.dwTypeData;
+      oldflags |= MF_POPUP;
 
       if (accel && bar_p)
        *accel_list = Fcons (make_char (accel), *accel_list);
@@ -383,7 +419,7 @@ populate_menu_add_item (HMENU menu, Lisp_Object path,
          Fputhash (hmenu_to_lisp_object (submenu), path, hash_tab);
        }
       UNGCPRO;
-    } 
+    }
   else if (VECTORP (item))
     {
       /* An ordinary item */
@@ -396,16 +432,19 @@ populate_menu_add_item (HMENU menu, Lisp_Object path,
       GCPRO2 (gui_item, *accel_list);
 
       if (!gui_item_included_p (gui_item, Vmenubar_configuration))
-      {
-       UNGCPRO;
-       goto done;
-      }
+       {
+         UNGCPRO;
+         goto done;
+       }
 
       if (!STRINGP (pgui_item->name))
        pgui_item->name = Feval (pgui_item->name);
 
       if (!gui_item_active_p (gui_item))
-       item_info.fState = MFS_GRAYED;
+       {
+         item_info.fState = MFS_GRAYED;
+         oldflags = MF_GRAYED;
+       }
 
       style = (NILP (pgui_item->selected) || NILP (Feval (pgui_item->selected))
               ? Qnil : pgui_item->style);
@@ -414,10 +453,13 @@ populate_menu_add_item (HMENU menu, Lisp_Object path,
        {
          item_info.fType |= MFT_RADIOCHECK;
          item_info.fState |= MFS_CHECKED;
+         oldflags |= MF_CHECKED; /* Can't support radio-button checkmarks
+                                    under 3.51 */
        }
       else if (EQ (style, Qtoggle))
        {
          item_info.fState |= MFS_CHECKED;
+         oldflags |= MF_CHECKED;
        }
 
       id = allocate_menu_item_id (path, pgui_item->name,
@@ -427,6 +469,9 @@ populate_menu_add_item (HMENU menu, Lisp_Object path,
       item_info.wID = (UINT) XINT (id);
       item_info.fType |= MFT_STRING;
       item_info.dwTypeData = displayable_menu_item (gui_item, bar_p, &accel);
+      olduidnewitem = item_info.wID;
+      oldflags |= MF_STRING;
+      oldlpnewitem = item_info.dwTypeData;
 
       if (accel && bar_p)
        *accel_list = Fcons (make_char (accel), *accel_list);
@@ -434,17 +479,18 @@ populate_menu_add_item (HMENU menu, Lisp_Object path,
       UNGCPRO;
     }
   else
-    {
-      signal_simple_error ("Malformed menu item descriptor", item);
-    }
+    syntax_error ("Malformed menu item descriptor", item);
 
   if (flush_right)
-    item_info.fType |= MFT_RIGHTJUSTIFY;
+    item_info.fType |= MFT_RIGHTJUSTIFY; /* can't support in 3.51 */
 
-  InsertMenuItem (menu, UINT_MAX, TRUE, &item_info);
+  if (xInsertMenuItemA)
+    xInsertMenuItemA (menu, UINT_MAX, TRUE, &item_info);
+  else
+    InsertMenu (menu, UINT_MAX, oldflags, olduidnewitem, oldlpnewitem);
 
 done:;
-}  
+}
 
 /*
  * This function is called from populate_menu and checksum_menu.
@@ -488,7 +534,7 @@ populate_or_checksum_helper (HMENU menu, Lisp_Object path, Lisp_Object desc,
 
   /* Check that menu name is specified when expected */
   if (NILP (pgui_item->name) && deep_p)
-    signal_simple_error ("Menu must have a name", desc);
+    syntax_error ("Menu must have a name", desc);
 
   /* Apply filter if specified */
   if (!NILP (pgui_item->filter))
@@ -514,7 +560,7 @@ populate_or_checksum_helper (HMENU menu, Lisp_Object path, Lisp_Object desc,
        checksum = HASH2 (checksum,
                          checksum_menu_item (XCAR (item_desc)));
     }
-  
+
   if (populate_p)
     {
       /* Remove the "(empty)" item, if there are other ones */
@@ -528,9 +574,10 @@ populate_or_checksum_helper (HMENU menu, Lisp_Object path, Lisp_Object desc,
        {
          CHECK_STRING (pgui_item->name);
          InsertMenu (menu, 0, MF_BYPOSITION | MF_STRING | MF_DISABLED,
-                     0, XSTRING_DATA(pgui_item->name));
+                     0, displayable_menu_item (gui_item, bar_p, NULL));
          InsertMenu (menu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
-         SetMenuDefaultItem (menu, 0, MF_BYPOSITION);
+         if (xSetMenuDefaultItem) /* not in NT 3.5x */
+           xSetMenuDefaultItem (menu, 0, MF_BYPOSITION);
        }
     }
 
@@ -631,12 +678,12 @@ prune_menubar (struct frame *f)
   if (menubar == NULL)
     return;
 
-  /* #### If a filter function has set desc to Qnil, this abort()
+  /* #### If a filter function has set desc to Qnil, this ABORT()
      triggers. To resolve, we must prevent filters explicitly from
      mangling with the active menu. In apply_filter probably?
      Is copy-tree on the whole menu too expensive? */
   if (NILP (desc))
-    /* abort(); */
+    /* ABORT(); */
     return;
 
   GCPRO1 (desc); /* just to be safe -- see above */
@@ -648,7 +695,7 @@ prune_menubar (struct frame *f)
 
   Fputhash (hmenu_to_lisp_object (menubar), Qnil,
            FRAME_MSWINDOWS_MENU_HASH_TABLE (f));
-  populate_menu (menubar, Qnil, desc, 
+  populate_menu (menubar, Qnil, desc,
                 FRAME_MSWINDOWS_MENU_HASH_TABLE (f), 1);
   UNGCPRO;
 }
@@ -671,12 +718,13 @@ mswindows_char_is_accelerator (struct frame *f, Emchar ch)
 {
   Lisp_Object hash = FRAME_MSWINDOWS_MENU_HASH_TABLE (f);
 
-  assert (HASH_TABLEP (hash));
+  if (NILP (hash))
+    return 0;
   /* !!#### not Mule-ized */
   return !NILP (memq_no_quit (make_char (tolower (ch)),
                              Fgethash (Qt, hash, Qnil)));
 }
-  
+
 \f
 /*------------------------------------------------------------------------*/
 /* Message handlers                                                       */
@@ -689,7 +737,7 @@ unsafe_handle_wm_initmenupopup_1 (HMENU menu, struct frame *f)
 
   Lisp_Object path, desc;
   struct gcpro gcpro1;
-
+  
   /* Find which guy is going to explode */
   path = Fgethash (hmenu_to_lisp_object (menu), current_hash_table, Qunbound);
   assert (!UNBOUNDP (path));
@@ -771,10 +819,9 @@ mswindows_handle_wm_command (struct frame *f, WORD id)
   XSETFRAME (frame, f);
   /* this used to call mswindows_enqueue_misc_user_event but that
      breaks customize because the misc_event gets eval'ed in some
-     cicumstances. Don't change it back unless you can fix the
+     circumstances. Don't change it back unless you can fix the
      customize problem also.*/
-  enqueue_misc_user_event (frame, fn, arg);
-  mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
+  mswindows_enqueue_misc_user_event (frame, fn, arg);
 
   UNGCPRO; /* data */
   return Qt;
@@ -868,6 +915,8 @@ mswindows_popup_menu (Lisp_Object menu_desc, Lisp_Object event)
        eev = NULL;
     }
 
+  popup_up_p++;
+
   /* Default is to put the menu at the point (10, 10) in frame */
   if (eev)
     {
@@ -883,17 +932,19 @@ mswindows_popup_menu (Lisp_Object menu_desc, Lisp_Object event)
   CHECK_CONS (menu_desc);
   CHECK_STRING (XCAR (menu_desc));
 
+  menu_cleanup (f);
+
   current_menudesc = menu_desc;
   current_hash_table =
     make_lisp_hash_table (10, HASH_TABLE_NON_WEAK, HASH_TABLE_EQUAL);
   menu = create_empty_popup_menu ();
   Fputhash (hmenu_to_lisp_object (menu), Qnil, current_hash_table);
   top_level_menu = menu;
-  
+
   /* see comments in menubar-x.c */
   if (zmacs_regions)
     zmacs_region_stays = 1;
-  
+
   ok = TrackPopupMenu (menu,
                       TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
                       pt.x, pt.y, 0,
@@ -901,7 +952,15 @@ mswindows_popup_menu (Lisp_Object menu_desc, Lisp_Object event)
 
   DestroyMenu (menu);
 
-  /* Signal a signal if caught by Track...() modal loop */
+  /* A WM_COMMAND is not issued until TrackPopupMenu returns. This
+     makes setting popup_up_p fairly pointless since we cannot keep
+     the menu up and dispatch events. Furthermore, we seem to have
+     little control over what happens to the menu when we click. */
+  popup_up_p--;
+
+  /* Signal a signal if caught by Track...() modal loop. */
+  /* I think this is pointless, the code hasn't actually put us in a
+     modal loop at this time -- andyp. */
   mswindows_unmodalize_signal_maybe ();
 
   /* This is probably the only real reason for failure */