From xemacs-m  Sun Sep 21 13:39:19 1997
Received: from norway.aosi.com (norway.aosi.net [207.242.152.23])
	by xemacs.org (8.8.5/8.8.5) with ESMTP id NAA26176;
	Sun, 21 Sep 1997 13:39:19 -0500 (CDT)
Received: from aosi.com ([207.242.153.45]) by norway.aosi.com
          (Post.Office MTA v3.1 release PO203a ID# 0-36402U1000L100S0)
          with ESMTP id AAA133; Sun, 21 Sep 1997 14:42:29 -0400
Sender: joel
Message-ID: <34256868.785268BF@aosi.com>
Date: Sun, 21 Sep 1997 14:33:12 -0400
From: Joel Peterson <tarzan@aosi.com>
Organization: Me Tarzan, you Jane?
X-Mailer: Mozilla 4.03 [en] (X11; I; Linux 2.0.27 i586)
MIME-Version: 1.0
To: Hrvoje Niksic <hniksic@srce.hr>, Steve Baur <steve@xemacs.org>,
        XEmacs Developers <xemacs-beta@xemacs.org>
Subject: Re: A problem with menu accelerators
References: <kigk9gb4fg3.fsf@jagor.srce.hr>
Content-Type: multipart/mixed; boundary="------------38F12C1640B53BFD2FD85E0D"

This is a multi-part message in MIME format.
--------------38F12C1640B53BFD2FD85E0D
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hrvoje Niksic wrote:
> 
> I have spotted a problem in the (otherwise terrific!) design of menu
> accelerators.  The trouble is, if you define your menus to have random
> %_ within the entry strings, then the simple things like
> 
> (add-menu-button '("File") "ha ha")
> 
> will not only miss the '("%_File") menu item, but they will add a
> new '("File") menu item to the menubar.  Yuck!
> 
> There are two ways of handling this:
> 
> 1) implement that the %_ are somehow ignored within any strings in
>    menubar functions;
> 
> 2) think out a new interface for adding accelerators, separating them
>    from the strings.
> 
> Solution #1 is hard to implement, but easy to use.  #2 is easy to
> implement, but hard to use.  Which one is worse, and which one is
> better?

#1 is actually not that hard, since menubar.el already calls downcase
prior to comparing menu item names, so it's pretty easy to replace that
with a different function call.

#2 might be better, but adds other problems.  It's actually already
implemented to some extent, via the :accelerator tag.  However, nothing
in the menu will be underlined.  The big problem with the :accelerator
tag is that if someone chooses to rename the File menu to XEmacs (for
example), the accelerator key would still be 'F', which doesn't make any
sense.  I think it's better for it to be nothing than for it to be
something that doesn't make sense.

An extent or string property could also be used to indicate the
accelerator key, but that makes specifying accelerator keys tedious.

I created a function in menubar.c which does both a downcase and removes
%_.  I tried your example and got a "ha ha" item at the bottom of the
"%_File" menu.

Attached is a patch against Beta 23.

Here are the ChangeLog entries for said patch:

src/ChangeLog

1997-09-21  Joel Peterson  <tarzan@aosi.com>

	* menubar.c (normalize-menu-item-name): New function.


lisp/Changelog

1997-09-21  Joel Peterson  <tarzan@aosi.com>

	* prim/menubar.el: use normalize-menu-item-name instead of downcase
	to compare menu item names.

-- 
"Spoon!"
 
                  Joel Peterson
                       Supreme Deputy of scratching Dogbert behind the
                       ears until he has little leg spasms.
--------------38F12C1640B53BFD2FD85E0D
Content-Type: text/plain; charset=us-ascii; name="menubar-patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="menubar-patch"

--- lisp/prim/menubar.el.orig	Sat Jul 19 18:11:26 1997
+++ lisp/prim/menubar.el	Sun Sep 21 13:45:47 1997
@@ -169,7 +169,7 @@
 If some menu in the ITEM-PATH-LIST does not exist, an error is signalled."
   (or (listp item-path-list)
       (signal 'wrong-type-argument (list 'listp item-path-list)))
-  (or parent (setq item-path-list (mapcar 'downcase item-path-list)))
+  (or parent (setq item-path-list (mapcar 'normalize-menu-item-name item-path-list)))
   (if (not (consp menubar))
       nil
     (let ((rest menubar)
@@ -181,7 +181,7 @@
       (while rest
 	(if (and (car rest)
 		 (equal (car item-path-list)
-			(downcase (if (vectorp (car rest))
+			(normalize-menu-item-name (if (vectorp (car rest))
 				      (aref (car rest) 0)
 				    (if (stringp (car rest))
 					(car rest)
@@ -199,7 +199,7 @@
 (defun add-menu-item-1 (leaf-p menu-path new-item before)
   ;; This code looks like it could be cleaned up some more
   ;; Do we really need 6 calls to find-menu-item?
-  (when before (setq before (downcase before)))
+  (when before (setq before (normalize-menu-item-name before)))
   (let* ((item-name
 	  (cond ((vectorp new-item) (aref new-item 0))
 		((consp   new-item) (car  new-item))
--- src/menubar.c.orig	Tue Sep  2 23:39:43 1997
+++ src/menubar.c	Sun Sep 21 11:47:54 1997
@@ -27,6 +27,7 @@
 #include <config.h>
 #include "lisp.h"
 
+#include "buffer.h"
 #include "device.h"
 #include "frame.h"
 #include "menubar.h"
@@ -178,11 +179,59 @@
   return Qnil;
 }
 
+DEFUN ("normalize-menu-item-name", Fnormalize_menu_item_name, 1, 2, 0, /*
+Convert a menu item name string into normal form.  Returns a new string.
+Menu item names should be converted to normal form before being compared.
+*/
+       (name, buffer))
+{
+  struct buffer *buf = decode_buffer (buffer, 0);
+  struct Lisp_String *n;
+  Charcount end;
+  int i;
+  Bufbyte *name_data;
+  Bufbyte *string_result;
+  Bufbyte *string_result_ptr;
+  Lisp_Object res;
+  Emchar elt;
+  int expecting_underscore = 0;
+  
+  CHECK_STRING (name);
+  
+  n = XSTRING (name);
+  end = string_char_length (n);
+  name_data = string_data (n);
+  
+  string_result = (Bufbyte *) alloca (end * MAX_EMCHAR_LEN);
+  string_result_ptr = string_result;
+  for (i = 0; i < end ; i++)
+    {
+      elt = charptr_emchar_n (name_data, i);
+      elt = DOWNCASE (buf, elt);
+      if (elt == '%')
+	expecting_underscore = 1;
+      else if (expecting_underscore)
+	{
+	  expecting_underscore = 0;
+	  if (elt != '_')
+	    {
+	      string_result_ptr += set_charptr_emchar (string_result_ptr, '%');
+	      string_result_ptr += set_charptr_emchar (string_result_ptr, elt);
+	    }
+	}
+      else
+	string_result_ptr += set_charptr_emchar (string_result_ptr, elt);
+    }
+
+  return make_string (string_result, string_result_ptr - string_result);
+}
+
 void
 syms_of_menubar (void)
 {
   defsymbol (&Qcurrent_menubar, "current-menubar");
   DEFSUBR (Fpopup_menu);
+  DEFSUBR (Fnormalize_menu_item_name);
 }
 
 void

--------------38F12C1640B53BFD2FD85E0D--

