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)