Subject: Re: hack for mouse popup menus in NT version of emacs19.34

From: [email-masked] (Mark Jungerman)
Date: Thu, 24 Oct 1996 07:51:16 -0700

Geoff Voelker writes:
> Yes, I'm very sorry about this, I haven't done anything on it yet.
> Too many things keep coming up...the latest being that I broke my leg
> on Monday playing soccer.
> 
> I'll have to get it from Stallman.  I'll try to get you more info in a
> week.
> 
> -geoff
> 

OK, thanks.  There is another more serious problem.  Note the following:

Jacob Colman writes:
> At 09:19 AM 10/23/96 -0700, you wrote:
> >
> >Hmm.  I don't know enough about imenu to try what you describe here.
> >The format expected by the new code for the second argument to
> >x-popup-menu is not the same as it was before (this is
> >probably a bug), so if the imenu code is using that it could explain
> >the problem.
> 
> Why did you change the behavior of the function?  Wouldn;t you want it to
> work the same way as the rest of Emacs expects it to?  imenu is a standard
> part of the distribution.  It generates an index of functions (mode
> sensitive) in a buffer.  If executed interactively, it splits the screen and
> displays the index.  if executed from a mouse click, it generates a pop-up.
> Another example of a menu-based elisp package is the msb package (also part
> of the distribution).  It is for those packages that I was interested in
> your mods.
> ---
> Jake Colman                     email: [email-masked]
> JNC Consulting Group Inc.       Phone: (914) 368-2765
> 42 Olympia Lane                 FAX  : (914) 368-2765
> Monsey, NY  10952
> 
> 

The bottom line is that the changes I made probably ought to be fixed to
agree with the standard format for the second argument to
x-popup-menu.  I will probably not have time to do this before the end
of the year due to extreme schedule constraints, and at least would
need a pointer to some description of what the standard format is
(maybe this is in some obvious place, but I recall being unable to
figure it out before - I may just have been confused because I was
trying to deduce it from code in w32menu.c that may never have been
operational).  I am hoping that 'someone' could look at the two versions
of w32menu.c and do the merge to get the standard format to work.  If so
we would be happy to take that back and change our elisp code to use the
standard format.  If not,  I will do it when I can get time.

---

From: [email-masked] (Mark Jungerman)
Date: Fri, 30 Aug 1996 16:29:50 -0700

Below are diffs for changes we made to the files src/w32fns.c and
src/w32menu.c in emacs19.34 to make x-popup-menu work with a second
argument that is a list.  We did this because we wanted to have mouse
popup menus ala xemacs, and the existing code didn't seem to be working.
This is a quick and dirty hack, but has seemed to work fairly robustly
for a few months now.  We would like to see some version of it get
merged into the mainline version, if you see fit.

The format of the list argument is somewhat different than the
description in docstring for x-popup-menu.  The elements are either
strings or conses.  A string makes a menu entry which is a dimmed
title, unselectable.  A cons produces a selectable item.  Typically
the car is a string which is the label in the resulting menu entry and
the cdr is the value returned by x-popup-menu when the entry is
selected.  If the cdr is itself a list, it is used as to define a 
cascading popup, as if x-popup-menu had been called with this list as
its second argument.  If the car of an entry is not a string, then it is
t.  This means that the cdr is a cons where the car is used as the label
and the cdr as the return value, even if the cdr is a list.  In other
words, it is a way of getting a list return value instead of a cascading
popup.

diff -cr orig/w32fns.c hacked/w32fns.c
*** orig/w32fns.c Wed Aug 28 20:57:08 1996
--- hacked/w32fns.c Fri Aug 30 14:47:02 1996
***************
*** 2891,2897 ****
  	  switch (msg.message)
  	    {
  	    case WM_EMACS_CREATEWINDOW:
! 	      win32_createwindow ((struct frame *) msg.wParam);
  	      PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0);
  	      break;
  	    case WM_EMACS_CREATESCROLLBAR:
--- 2891,2903 ----
  	  switch (msg.message)
  	    {
  	    case WM_EMACS_CREATEWINDOW:
! 	      if (msg.lParam) {
! 		extern BOOL win32_popupmenu();
! 		win32_popupmenu(&msg);
! 		button_state = 0;
! 		one_win32_display_info.grabbed = 0;
! 	      } else
! 		win32_createwindow ((struct frame *) msg.wParam);
  	      PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0);
  	      break;
  	    case WM_EMACS_CREATESCROLLBAR:

diff -cr orig/w32menu.c hacked/w32menu.c
*** orig/w32menu.c Wed Aug 28 20:57:08 1996
--- hacked/w32menu.c Fri Aug 30 14:54:00 1996
***************
*** 72,79 ****
  static HMENU keymap_panes ();
  static HMENU single_keymap_panes ();
  static HMENU list_of_panes ();
- static HMENU list_of_items ();
- 
  static HMENU create_menu_items ();
  
  /* Initialize the menu_items structure if we haven't already done so.
--- 72,77 ----
***************
*** 609,615 ****
    Lisp_Object tail;
    HMENU hmenu;
    
!   hmenu = CreateMenu ();
    if (hmenu == NULL) return NULL;
    
    //    init_menu_items (lpmm);
--- 607,613 ----
    Lisp_Object tail;
    HMENU hmenu;
    
!   hmenu = CreatePopupMenu ();
    if (hmenu == NULL) return NULL;
    
    //    init_menu_items (lpmm);
***************
*** 620,635 ****
        HMENU new_hmenu;
  
        elt = Fcar (tail);
!       pane_name = Fcar (elt);
!       CHECK_STRING (pane_name, 0);
!       pane_data = Fcdr (elt);
!       CHECK_CONS (pane_data, 0);
  
-       new_hmenu = list_of_items (lpmm, pane_data);
-       if (new_hmenu == NULL) goto error;
- 
-       AppendMenu (hmenu, MF_POPUP, (UINT)new_hmenu,
- 		  (char *) XSTRING (pane_name)->data);
      }
  
    return (hmenu);
--- 618,654 ----
        HMENU new_hmenu;
  
        elt = Fcar (tail);
!       if (STRINGP (elt))
! 	add_menu_item (lpmm, hmenu, elt, 0, Qnil);
!       else if (NILP (elt))
! 	add_menu_item (lpmm, hmenu, elt, 0, Qnil);
!       else 
! 	{
! 	  int list_data_is_sub_menu = 1;
! 	  CHECK_CONS (elt, 0);
! 	  pane_name = Fcar (elt);
! 	  if (EQ (pane_name, Qt))
! 	    {
! 	      list_data_is_sub_menu = 0;
! 	      elt = Fcdr(elt);
! 	      CHECK_CONS (elt, 0);
! 	      pane_name = Fcar (elt);
! 	    }
! 	  CHECK_STRING (pane_name, 0);
! 	  pane_data = Fcdr (elt);
! 	  if (CONSP(pane_data) && list_data_is_sub_menu)
! 	    {
! 	      new_hmenu = list_of_panes (lpmm, pane_data);
! 	      if (new_hmenu == NULL) goto error;
! 	      AppendMenu (hmenu, MF_POPUP, (UINT)new_hmenu,
! 			  (char *) XSTRING (pane_name)->data);
! 	    }
! 	  else
! 	    {
! 	      add_menu_item (lpmm, hmenu, pane_name, 1, pane_data);
! 	    }
! 	}
  
      }
  
    return (hmenu);
***************
*** 640,676 ****
    return (NULL);
  }
  
- /* Push the items in a single pane defined by the alist PANE.  */
- 
- static HMENU 
- list_of_items (lpmm, pane)
-      menu_map * lpmm;
-      Lisp_Object pane;
- {
-   Lisp_Object tail, item, item1;
-   HMENU hmenu;
- 
-   hmenu = CreateMenu ();
-   if (hmenu == NULL) return NULL;
- 
-   for (tail = pane; !NILP (tail); tail = Fcdr (tail))
-     {
-       item = Fcar (tail);
-       if (STRINGP (item))
- 	add_menu_item (lpmm, hmenu, item, Qnil, Qnil);
-       else if (NILP (item))
- 	add_left_right_boundary ();
-       else
- 	{
- 	  CHECK_CONS (item, 0);
- 	  item1 = Fcar (item);
- 	  CHECK_STRING (item1, 1);
- 	  add_menu_item (lpmm, hmenu, item1, Qt, Fcdr (item));
- 	}
-     }
- 
-   return (hmenu);
- }
  
  
  HMENU 
--- 659,664 ----
***************
*** 747,756 ****
    else
      {
        /* We were given an old-fashioned menu.  */
!       title = Fcar (menu);
!       CHECK_STRING (title, 1);
! 	
!       hmenu = list_of_panes (lpmm, Fcdr (menu));
      }
    
    return (hmenu);
--- 735,741 ----
    else
      {
        /* We were given an old-fashioned menu.  */
!       hmenu = list_of_panes (lpmm, menu);
      }
    
    return (hmenu);
***************
*** 992,1027 ****
    return (event);
  }
  
- static Lisp_Object 
- get_list_of_items_event (pane, lpnum)
-      Lisp_Object pane;
-      int * lpnum;
- {
-   Lisp_Object tail, item, item1;
-   
-   for (tail = pane; !NILP (tail); tail = Fcdr (tail))
-     {
-       item = Fcar (tail);
-       if (STRINGP (item))
- 	{
- 	  if (-- (*lpnum) == 0) 
- 	    {
- 	      return (Qnil);
- 	    }
- 	}
-       else if (!NILP (item))
- 	{
- 	  if (--(*lpnum) == 0) 
- 	    {
- 	      CHECK_CONS (item, 0);
- 	      return (Fcdr (item));
- 	    }
- 	}
-     }
-   
-   return (Qnil);
- }
- 
  /* Push all the panes and items of a menu described by the
     alist-of-alists MENU.
     This handles old-fashioned calls to x-popup-menu.  */
--- 977,982 ----
***************
*** 1039,1053 ****
        Lisp_Object event;
  
        elt = Fcar (tail);
!       pane_data = Fcdr (elt);
!       CHECK_CONS (pane_data, 0);
! 
!       event = get_list_of_items_event (pane_data, lpnum);
! 
!       if (*lpnum <= 0) 
  	{
! 	  return (event);
  	}
      }
  
    return (Qnil);
--- 994,1029 ----
        Lisp_Object event;
  
        elt = Fcar (tail);
!       if (STRINGP (elt) || NILP (elt))
  	{
! 	  if (-- (*lpnum) == 0) 
! 	    {
! 	      return (Qnil);
! 	    }
  	}
+       else
+ 	{
+ 	  int list_data_is_sub_menu = 1;
+ 	  CHECK_CONS (elt, 0);
+ 	  if (EQ (Fcar(elt), Qt)) {
+ 	    list_data_is_sub_menu = 0;
+ 	    elt = Fcdr (elt);
+ 	    CHECK_CONS (elt, 0);
+ 	  }
+ 	  pane_data = Fcdr (elt);
+ 	  if (CONSP (pane_data) && list_data_is_sub_menu) {
+ 	    event = get_list_of_panes_event (pane_data, lpnum);
+ 	    if (*lpnum <= 0) 
+ 	      {
+ 		return (event);
+ 	      }
+ 	  } else {
+ 	    if (-- (*lpnum) == 0) 
+ 	      {
+ 		return (pane_data);
+ 	      }
+ 	  }
+ 	}
      }
  
    return (Qnil);
***************
*** 1096,1107 ****
    else
      {
        /* We were given an old-fashioned menu.  */
!       event = get_list_of_panes_event (Fcdr (menu), lpnum);
      }
  
    return (event);
  }
  
  DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
         "Pop up a deck-of-cards menu and return user's selection.\n\
  POSITION is a position specification.  This is either a mouse button event\n\
--- 1072,1092 ----
    else
      {
        /* We were given an old-fashioned menu.  */
!       event = get_list_of_panes_event (menu, lpnum);
      }
  
    return (event);
  }
  
+ typedef struct MY_POPUP {
+   int xpos;
+   int ypos;
+   Lisp_Object menu;
+   HMENU hmenu;
+   char **error_name;
+   Lisp_Object selection;
+ } MY_POPUP;
+ 
  DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
         "Pop up a deck-of-cards menu and return user's selection.\n\
  POSITION is a position specification.  This is either a mouse button event\n\
***************
*** 1240,1246 ****
    /* Display them in a menu.  */
    BLOCK_INPUT;
    
!   selection = win32menu_show (f, xpos, ypos, menu, &hmenu, &error_name);
    
    UNBLOCK_INPUT;
    
--- 1225,1243 ----
    /* Display them in a menu.  */
    BLOCK_INPUT;
    
!   {
!     MSG msg;
!     MY_POPUP x;
!     x.xpos = xpos;
!     x.ypos = ypos;
!     x.menu = menu;
!     x.hmenu = hmenu;
!     x.error_name = &error_name;
! 
!     PostThreadMessage (dwWinThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, (LPARAM)&x);
!     GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
!     selection = x.selection;
!   }
    
    UNBLOCK_INPUT;
    
***************
*** 1253,1258 ****
--- 1250,1264 ----
    return selection;
  }
  
+ BOOL win32_popupmenu(msg)
+ MSG *msg;
+ {
+   FRAME_PTR f = (FRAME_PTR)msg->wParam;
+   MY_POPUP *x = (MY_POPUP *)msg->lParam;
+   x->selection = win32menu_show (f, x->xpos, x->ypos, x->menu, x->hmenu, x->error_name);
+   return *x->error_name ? FALSE : TRUE;
+ }
+ 
  DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 2, 0,
         "Pop up a dialog box and return user's selection.\n\
  POSITION specifies which frame to use.\n\
***************
*** 1702,1715 ****
    
    /* Display the menu.  */
    menu_selection = TrackPopupMenu (hmenu,
! 				   0x10,
  				   pos.x, pos.y,
  				   0,
  				   FRAME_WIN32_WINDOW (f),
  				   NULL);
!   if (menu_selection == -1)
      {
!       *error = "Invalid menu specification";
        return Qnil;
      }
    
--- 1708,1727 ----
    
    /* Display the menu.  */
    menu_selection = TrackPopupMenu (hmenu,
! 				   TPM_RETURNCMD|TPM_RIGHTBUTTON,
  				   pos.x, pos.y,
  				   0,
  				   FRAME_WIN32_WINDOW (f),
  				   NULL);
!   if (menu_selection == 0)
      {
!       static char buf[100];
!       int e = GetLastError();
!       if (e != 5 /* EIO */)
! 	sprintf(&buf[0],"Invalid menu specification: %d", e);
!       else
! 	sprintf(&buf[0],"Menu aborted.");
!       *error = &buf[0];
        return Qnil;
      }
    
***************
*** 1719,1725 ****
  #if 1
    if (menu_selection > 0)
      {
!       return get_menu_event (menu, menu_selection);
      }
  #else
    if (menu_selection > 0 && menu_selection <= lpmm->menu_items_used)
--- 1731,1737 ----
  #if 1
    if (menu_selection > 0)
      {
!       return get_menu_event (menu, &menu_selection);
      }
  #else
    if (menu_selection > 0 && menu_selection <= lpmm->menu_items_used)