From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Chong Yidong Newsgroups: gmane.emacs.devel Subject: Re: NeXTstep (GNUstep/Cocoa) port and merging Date: Sun, 08 Jun 2008 00:48:26 -0400 Message-ID: <87ej78v8f9.fsf@stupidchicken.com> References: <87od6ckbv7.fsf@stupidchicken.com> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: ger.gmane.org 1212900525 15009 80.91.229.12 (8 Jun 2008 04:48:45 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sun, 8 Jun 2008 04:48:45 +0000 (UTC) Cc: Adrian Robert , emacs-devel To: Stefan Monnier Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sun Jun 08 06:49:26 2008 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1K5CqK-0004YU-8j for ged-emacs-devel@m.gmane.org; Sun, 08 Jun 2008 06:49:25 +0200 Original-Received: from localhost ([127.0.0.1]:56065 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1K5CpW-0003kP-Md for ged-emacs-devel@m.gmane.org; Sun, 08 Jun 2008 00:48:34 -0400 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1K5CpQ-0003jx-Kx for emacs-devel@gnu.org; Sun, 08 Jun 2008 00:48:28 -0400 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1K5CpP-0003jZ-In for emacs-devel@gnu.org; Sun, 08 Jun 2008 00:48:28 -0400 Original-Received: from [199.232.76.173] (port=59633 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1K5CpP-0003jW-Ef for emacs-devel@gnu.org; Sun, 08 Jun 2008 00:48:27 -0400 Original-Received: from c-98-216-111-182.hsd1.ma.comcast.net ([98.216.111.182]:11750 helo=furry) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1K5CpO-0002xA-NF for emacs-devel@gnu.org; Sun, 08 Jun 2008 00:48:27 -0400 Original-Received: by furry (Postfix, from userid 1000) id 6FA9FC050; Sun, 8 Jun 2008 00:48:26 -0400 (EDT) In-Reply-To: <87od6ckbv7.fsf@stupidchicken.com> (Chong Yidong's message of "Sat, 07 Jun 2008 20:29:32 -0400") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.0.60 (gnu/linux) X-detected-kernel: by monty-python.gnu.org: Linux 2.6 (newer, 2) X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:98666 Archived-At: Chong Yidong writes: > Stefan Monnier writes: > >>> One area it would be nice to have some feedback on is the added file >>> "nsmenu_common.c". This file of about 1000 lines contains code that is >>> more or less duplicated (modulo some divergence) across {x,w32,mac}menu.c, >>> and is concerned mainly with mediating between lisp and C representations >>> of menus. I followed xmenu.c when creating the common file. It would be >>> good to change this to "menu_common.c" and have the other GUIs use it. >> >> Yes, it would indeed be good. I've already several times intended to >> make a similar change but never got around to really do it. If someone >> could take this part of the Emacs.app patch and make it independent from >> Emacs.app, that would be great. > > I've been working on this, and it's nearly ready. I'll check in a > platform-independent menu.c sometime this week. It will probably need a > bit of help from those with access to w32 and mac to get it working > properly on those platforms. > > I'll ping the list when it's checked in. I've added a new file menu.c to the CVS trunk. This contains platform-independent parts of the menu code, taken from xmenu.c. Some definitions have also been moved into keyboard.h. Currently, I have only removed code from xmenu.c, and menu.c is only compiled in when HAVE_X_WINDOWS is defined. I cannot test it on Windows or Mac OS, and I don't want to break things. I think the following additional patch should DTRT on Windows, but it is 100% untested. Could someone try it? Also, could someone try write up the analogous code for Mac OS? Please let me know if there are problems. *** trunk/src/Makefile.in.~1.386.~ 2008-06-07 23:59:44.000000000 -0400 --- trunk/src/Makefile.in 2008-06-08 00:44:08.000000000 -0400 *************** *** 539,545 **** #endif /* HAVE_X_WINDOWS */ #endif /* HAVE_WINDOW_SYSTEM */ ! #ifdef HAVE_X_WINDOWS MENU_OBJ = menu.o #endif --- 539,545 ---- #endif /* HAVE_X_WINDOWS */ #endif /* HAVE_WINDOW_SYSTEM */ ! #if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI) MENU_OBJ = menu.o #endif *** trunk/src/keyboard.h.~1.84.~ 2008-06-08 00:06:07.000000000 -0400 --- trunk/src/keyboard.h 2008-06-08 00:43:45.000000000 -0400 *************** *** 253,259 **** /* Not nil if item is enabled. */ #define ITEM_PROPERTY_ENABLE 8 ! #ifdef HAVE_X_WINDOWS /* This holds a Lisp vector that holds the results of decoding the keymaps or alist-of-alists that specify a menu. --- 253,259 ---- /* Not nil if item is enabled. */ #define ITEM_PROPERTY_ENABLE 8 ! #if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI) /* This holds a Lisp vector that holds the results of decoding the keymaps or alist-of-alists that specify a menu. *** trunk/src/w32menu.c~ 2008-06-07 23:11:45.000000000 -0400 --- trunk/src/w32menu.c 2008-06-07 20:53:21.000000000 -0400 *************** *** 51,130 **** #undef HAVE_DIALOGS /* TODO: Implement native dialogs. */ /******************************************************************/ - /* Definitions copied from lwlib.h */ - - typedef void * XtPointer; - typedef char Boolean; - - enum button_type - { - BUTTON_TYPE_NONE, - BUTTON_TYPE_TOGGLE, - BUTTON_TYPE_RADIO - }; - - /* This structure is based on the one in ../lwlib/lwlib.h, modified - for Windows. */ - typedef struct _widget_value - { - /* name of widget */ - Lisp_Object lname; - char* name; - /* value (meaning depend on widget type) */ - char* value; - /* keyboard equivalent. no implications for XtTranslations */ - Lisp_Object lkey; - char* key; - /* Help string or nil if none. - GC finds this string through the frame's menu_bar_vector - or through menu_items. */ - Lisp_Object 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 - /* true if was edited (maintained by get_value) */ - Boolean edited; - /* true if has changed (maintained by lw library) */ - change_type change; - /* true if this widget itself has changed, - but not counting the other widgets found in the `next' field. */ - change_type this_one_change; - #endif - /* Contents of the sub-widgets, also selected slot for checkbox */ - struct _widget_value* contents; - /* data passed to callback */ - XtPointer call_data; - /* next one in the list */ - struct _widget_value* next; - #if 0 - /* slot for the toolkit dependent part. Always initialize to NULL. */ - void* toolkit_data; - /* tell us if we should free the toolkit data slot when freeing the - widget_value itself. */ - Boolean free_toolkit_data; - - /* we resource the widget_value structures; this points to the next - one on the free list if this one has been deallocated. - */ - struct _widget_value *free_list; - #endif - } widget_value; - - /* Local memory management */ - #define local_heap (GetProcessHeap ()) - #define local_alloc(n) (HeapAlloc (local_heap, HEAP_ZERO_MEMORY, (n))) - #define local_free(p) (HeapFree (local_heap, 0, ((LPVOID) (p)))) - - #define malloc_widget_value() ((widget_value *) local_alloc (sizeof (widget_value))) - #define free_widget_value(wv) (local_free ((wv))) - - /******************************************************************/ #ifndef TRUE #define TRUE 1 --- 51,56 ---- *************** *** 180,250 **** static Lisp_Object w32_menu_show P_ ((FRAME_PTR, int, int, int, int, Lisp_Object, char **)); - static void keymap_panes P_ ((Lisp_Object *, int, int)); - static void single_keymap_panes P_ ((Lisp_Object, Lisp_Object, Lisp_Object, - int, int)); - static void single_menu_item P_ ((Lisp_Object, Lisp_Object, - Lisp_Object *, int, int)); - static void list_of_panes P_ ((Lisp_Object)); - static void list_of_items P_ ((Lisp_Object)); void w32_free_menu_strings P_((HWND)); - /* This holds a Lisp vector that holds the results of decoding - the keymaps or alist-of-alists that specify a menu. - - It describes the panes and items within the panes. - - Each pane is described by 3 elements in the vector: - t, the pane name, the pane's prefix key. - Then follow the pane's items, with 5 elements per item: - the item string, the enable flag, the item's value, - the definition, and the equivalent keyboard key's description string. - - In some cases, multiple levels of menus may be described. - A single vector slot containing nil indicates the start of a submenu. - A single vector slot containing lambda indicates the end of a submenu. - The submenu follows a menu item which is the way to reach the submenu. - - A single vector slot containing quote indicates that the - following items should appear on the right of a dialog box. - - Using a Lisp vector to hold this information while we decode it - takes care of protecting all the data from GC. */ - - #define MENU_ITEMS_PANE_NAME 1 - #define MENU_ITEMS_PANE_PREFIX 2 - #define MENU_ITEMS_PANE_LENGTH 3 - - 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; - - /* Number of slots currently allocated in menu_items. */ - static int menu_items_allocated; - - /* This is the index in menu_items of the first empty slot. */ - static int menu_items_used; - - /* The number of panes currently recorded in menu_items, - excluding those within submenus. */ - static int menu_items_n_panes; - - /* Current depth within submenus. */ - static int menu_items_submenu_depth; - 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. --- 106,117 ---- static Lisp_Object w32_menu_show P_ ((FRAME_PTR, int, int, int, int, Lisp_Object, char **)); void w32_free_menu_strings P_((HWND)); static int next_menubar_widget_id; + extern widget_value *xmalloc_widget_value P_ ((void)); + /* 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. *************** *** 279,504 **** return 0; } - /* Initialize the menu_items structure if we haven't already done so. - Also mark it as currently empty. */ - - static void - init_menu_items () - { - if (NILP (menu_items)) - { - menu_items_allocated = 60; - menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil); - } - - menu_items_used = 0; - menu_items_n_panes = 0; - menu_items_submenu_depth = 0; - } - - /* Call at the end of generating the data in menu_items. - This fills in the number of items in the last pane. */ - - static void - finish_menu_items () - { - } - - /* Call when finished using the data for the current menu - in menu_items. */ - - static void - discard_menu_items () - { - /* Free the structure if it is especially large. - Otherwise, hold on to it, to save time. */ - if (menu_items_allocated > 200) - { - menu_items = Qnil; - menu_items_allocated = 0; - } - } - - /* Make the menu_items vector twice as large. */ - - static void - grow_menu_items () - { - menu_items_allocated *= 2; - menu_items = larger_vector (menu_items, menu_items_allocated, Qnil); - } - - /* Begin a submenu. */ - - static void - push_submenu_start () - { - if (menu_items_used + 1 > menu_items_allocated) - grow_menu_items (); - - ASET (menu_items, menu_items_used, Qnil); - menu_items_used++; - menu_items_submenu_depth++; - } - - /* End a submenu. */ - - static void - push_submenu_end () - { - if (menu_items_used + 1 > menu_items_allocated) - grow_menu_items (); - - ASET (menu_items, menu_items_used, Qlambda); - menu_items_used++; - menu_items_submenu_depth--; - } - - /* Indicate boundary between left and right. */ - - static void - push_left_right_boundary () - { - if (menu_items_used + 1 > menu_items_allocated) - grow_menu_items (); - - ASET (menu_items, menu_items_used, Qquote); - menu_items_used++; - } - - /* Start a new menu pane in menu_items. - NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */ - - static void - push_menu_pane (name, prefix_vec) - Lisp_Object name, prefix_vec; - { - if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated) - grow_menu_items (); - - if (menu_items_submenu_depth == 0) - menu_items_n_panes++; - ASET (menu_items, menu_items_used, Qt); menu_items_used++; - ASET (menu_items, menu_items_used, name); menu_items_used++; - ASET (menu_items, menu_items_used, prefix_vec); menu_items_used++; - } - - /* 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, 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 (); - - ASET (menu_items, menu_items_used, name); menu_items_used++; - ASET (menu_items, menu_items_used, enable); menu_items_used++; - ASET (menu_items, menu_items_used, key); menu_items_used++; - ASET (menu_items, menu_items_used, equiv); menu_items_used++; - ASET (menu_items, menu_items_used, def); menu_items_used++; - ASET (menu_items, menu_items_used, type); menu_items_used++; - ASET (menu_items, menu_items_used, selected); menu_items_used++; - ASET (menu_items, menu_items_used, help); menu_items_used++; - } - - /* Look through KEYMAPS, a vector of keymaps that is NMAPS long, - and generate menu panes for them in menu_items. - If NOTREAL is nonzero, - don't bother really computing whether an item is enabled. */ - - static void - keymap_panes (keymaps, nmaps, notreal) - Lisp_Object *keymaps; - int nmaps; - int notreal; - { - int mapno; - - init_menu_items (); - - /* Loop over the given keymaps, making a pane for each map. - But don't make a pane that is empty--ignore that map instead. - P is the number of panes we have made so far. */ - for (mapno = 0; mapno < nmaps; mapno++) - single_keymap_panes (keymaps[mapno], - Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10); - - finish_menu_items (); - } - - /* This is a recursive subroutine of keymap_panes. - It handles one keymap, KEYMAP. - The other arguments are passed along - or point to local variables of the previous function. - If NOTREAL is nonzero, only check for equivalent key bindings, don't - evaluate expressions in menu items and don't make any menu. - - If we encounter submenus deeper than MAXDEPTH levels, ignore them. */ - - static void - single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth) - Lisp_Object keymap; - Lisp_Object pane_name; - Lisp_Object prefix; - int notreal; - int maxdepth; - { - Lisp_Object pending_maps = Qnil; - Lisp_Object tail, item; - struct gcpro gcpro1, gcpro2; - - if (maxdepth <= 0) - return; - - push_menu_pane (pane_name, prefix); - - for (tail = keymap; CONSP (tail); tail = XCDR (tail)) - { - GCPRO2 (keymap, pending_maps); - /* Look at each key binding, and if it is a menu item add it - to this menu. */ - item = XCAR (tail); - if (CONSP (item)) - single_menu_item (XCAR (item), XCDR (item), - &pending_maps, notreal, maxdepth); - else if (VECTORP (item)) - { - /* Loop over the char values represented in the vector. */ - int len = ASIZE (item); - int c; - for (c = 0; c < len; c++) - { - Lisp_Object character; - XSETFASTINT (character, c); - single_menu_item (character, AREF (item, c), - &pending_maps, notreal, maxdepth); - } - } - UNGCPRO; - } - - /* Process now any submenus which want to be panes at this level. */ - while (!NILP (pending_maps)) - { - Lisp_Object elt, eltcdr, string; - elt = Fcar (pending_maps); - eltcdr = XCDR (elt); - string = XCAR (eltcdr); - /* We no longer discard the @ from the beginning of the string here. - Instead, we do this in w32_menu_show. */ - single_keymap_panes (Fcar (elt), string, - XCDR (eltcdr), notreal, maxdepth - 1); - pending_maps = Fcdr (pending_maps); - } - } - /* This is a subroutine of single_keymap_panes that handles one keymap entry. KEY is a key in a keymap and ITEM is its binding. --- 146,151 ---- *************** *** 564,621 **** } } - /* 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. */ - - static void - list_of_panes (menu) - Lisp_Object menu; - { - Lisp_Object tail; - - init_menu_items (); - - for (tail = menu; CONSP (tail); tail = XCDR (tail)) - { - Lisp_Object elt, pane_name, pane_data; - elt = XCAR (tail); - pane_name = Fcar (elt); - CHECK_STRING (pane_name); - push_menu_pane (pane_name, Qnil); - pane_data = Fcdr (elt); - CHECK_CONS (pane_data); - list_of_items (pane_data); - } - - finish_menu_items (); - } - - /* Push the items in a single pane defined by the alist PANE. */ - - static void - list_of_items (pane) - Lisp_Object pane; - { - Lisp_Object tail, item, item1; - - for (tail = pane; CONSP (tail); tail = XCDR (tail)) - { - item = XCAR (tail); - if (STRINGP (item)) - push_menu_item (item, Qnil, Qnil, Qt, Qnil, Qnil, Qnil, Qnil); - else if (NILP (item)) - push_left_right_boundary (); - else - { - CHECK_CONS (item); - item1 = Fcar (item); - CHECK_STRING (item1); - push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil, Qnil, Qnil, Qnil); - } - } - } - DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0, doc: /* Pop up a deck-of-cards menu and return user's selection. POSITION is a position specification. This is either a mouse button --- 211,216 ---- *************** *** 1091,1406 **** w32_free_menu_strings (FRAME_W32_WINDOW (f)); f->output_data.w32->menubar_active = 0; } - - /* Allocate a widget_value, blocking input. */ - - widget_value * - xmalloc_widget_value () - { - widget_value *value; - - BLOCK_INPUT; - value = malloc_widget_value (); - UNBLOCK_INPUT; - - return value; - } - - /* This recursively calls free_widget_value on the tree of widgets. - It must free all data that was malloc'ed for these widget_values. - In Emacs, many slots are pointers into the data of Lisp_Strings, and - must be left alone. */ - - void - free_menubar_widget_value_tree (wv) - widget_value *wv; - { - if (! wv) return; - - wv->name = wv->value = wv->key = (char *) 0xDEADBEEF; - - if (wv->contents && (wv->contents != (widget_value*)1)) - { - free_menubar_widget_value_tree (wv->contents); - wv->contents = (widget_value *) 0xDEADBEEF; - } - if (wv->next) - { - free_menubar_widget_value_tree (wv->next); - wv->next = (widget_value *) 0xDEADBEEF; - } - BLOCK_INPUT; - free_widget_value (wv); - UNBLOCK_INPUT; - } - - /* Set up data i menu_items for a menu bar item - whose event type is ITEM_KEY (with string ITEM_NAME) - and whose contents come from the list of keymaps MAPS. */ - - static int - parse_single_submenu (item_key, item_name, maps) - Lisp_Object item_key, item_name, maps; - { - Lisp_Object length; - int len; - Lisp_Object *mapvec; - int i; - int top_level_items = 0; - - length = Flength (maps); - len = XINT (length); - - /* Convert the list MAPS into a vector MAPVEC. */ - mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object)); - for (i = 0; i < len; i++) - { - mapvec[i] = Fcar (maps); - maps = Fcdr (maps); - } - - /* Loop over the given keymaps, making a pane for each map. - But don't make a pane that is empty--ignore that map instead. */ - for (i = 0; i < len; i++) - { - if (SYMBOLP (mapvec[i]) - || (CONSP (mapvec[i]) && !KEYMAPP (mapvec[i]))) - { - /* Here we have a command at top level in the menu bar - 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, Qnil, Qnil, Qnil); - } - else - { - Lisp_Object prompt; - prompt = Fkeymap_prompt (mapvec[i]); - single_keymap_panes (mapvec[i], - !NILP (prompt) ? prompt : item_name, - item_key, 0, 10); - } - } - - return top_level_items; - } - - - /* Create a tree of widget_value objects - representing the panes and items - in menu_items starting at index START, up to index END. */ - - static widget_value * - digest_single_submenu (start, end, top_level_items) - int start, end, top_level_items; - { - widget_value *wv, *prev_wv, *save_wv, *first_wv; - int i; - int submenu_depth = 0; - widget_value **submenu_stack; - - submenu_stack - = (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); - wv = xmalloc_widget_value (); - wv->name = "menu"; - wv->value = 0; - wv->enabled = 1; - wv->button_type = BUTTON_TYPE_NONE; - wv->help = Qnil; - first_wv = wv; - save_wv = 0; - prev_wv = 0; - - /* Loop over all panes and items made by the preceding call - to parse_single_submenu and construct a tree of widget_value objects. - Ignore the panes and items used by previous calls to - digest_single_submenu, even though those are also in menu_items. */ - i = start; - while (i < end) - { - if (EQ (AREF (menu_items, i), Qnil)) - { - submenu_stack[submenu_depth++] = save_wv; - save_wv = prev_wv; - prev_wv = 0; - i++; - } - else if (EQ (AREF (menu_items, i), Qlambda)) - { - prev_wv = save_wv; - save_wv = submenu_stack[--submenu_depth]; - i++; - } - else if (EQ (AREF (menu_items, i), Qt) - && submenu_depth != 0) - i += MENU_ITEMS_PANE_LENGTH; - /* Ignore a nil in the item list. - It's meaningful only for dialog boxes. */ - else if (EQ (AREF (menu_items, i), Qquote)) - i += 1; - else if (EQ (AREF (menu_items, i), Qt)) - { - /* Create a new pane. */ - Lisp_Object pane_name, prefix; - char *pane_string; - - pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME); - prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); - - if (STRINGP (pane_name)) - { - if (unicode_append_menu) - /* Encode as UTF-8 for now. */ - pane_name = ENCODE_UTF_8 (pane_name); - else if (STRING_MULTIBYTE (pane_name)) - pane_name = ENCODE_SYSTEM (pane_name); - - ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name); - } - - pane_string = (NILP (pane_name) - ? "" : (char *) SDATA (pane_name)); - /* If there is just one top-level pane, put all its items directly - under the top-level menu. */ - if (menu_items_n_panes == 1) - pane_string = ""; - - /* If the pane has a meaningful name, - make the pane a top-level menu item - with its items as a submenu beneath it. */ - if (strcmp (pane_string, "")) - { - wv = xmalloc_widget_value (); - if (save_wv) - save_wv->next = wv; - else - first_wv->contents = wv; - wv->lname = pane_name; - /* Set value to 1 so update_submenu_strings can handle '@' */ - wv->value = (char *) 1; - wv->enabled = 1; - wv->button_type = BUTTON_TYPE_NONE; - wv->help = Qnil; - } - save_wv = wv; - prev_wv = 0; - i += MENU_ITEMS_PANE_LENGTH; - } - else - { - /* Create a new item within current pane. */ - Lisp_Object item_name, enable, descrip, def, type, selected; - Lisp_Object help; - - item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME); - enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE); - descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY); - def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION); - type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE); - selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED); - help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP); - - if (STRINGP (item_name)) - { - if (unicode_append_menu) - item_name = ENCODE_UTF_8 (item_name); - else if (STRING_MULTIBYTE (item_name)) - item_name = ENCODE_SYSTEM (item_name); - - ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name); - } - - if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) - { - descrip = ENCODE_SYSTEM (descrip); - ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip); - } - - wv = xmalloc_widget_value (); - if (prev_wv) - prev_wv->next = wv; - else - save_wv->contents = wv; - - wv->lname = item_name; - if (!NILP (descrip)) - wv->lkey = descrip; - wv->value = 0; - /* The EMACS_INT cast avoids a warning. There's no problem - 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)) - help = Qnil; - - wv->help = help; - - prev_wv = wv; - - i += MENU_ITEMS_ITEM_LENGTH; - } - } - - /* If we have just one "menu item" - that was originally a button, return it by itself. */ - if (top_level_items && first_wv->contents && first_wv->contents->next == 0) - { - wv = first_wv->contents; - free_widget_value (first_wv); - return wv; - } - - return first_wv; - } - - - /* Walk through the widget_value tree starting at FIRST_WV and update - the char * pointers from the corresponding lisp values. - We do this after building the whole tree, since GC may happen while the - tree is constructed, and small strings are relocated. So we must wait - until no GC can happen before storing pointers into lisp values. */ - static void - update_submenu_strings (first_wv) - widget_value *first_wv; - { - widget_value *wv; - - for (wv = first_wv; wv; wv = wv->next) - { - if (wv->lname && ! NILP (wv->lname)) - { - wv->name = SDATA (wv->lname); - - /* Ignore the @ that means "separate pane". - This is a kludge, but this isn't worth more time. */ - if (wv->value == (char *)1) - { - if (wv->name[0] == '@') - wv->name++; - wv->value = 0; - } - } - - if (wv->lkey && ! NILP (wv->lkey)) - wv->key = SDATA (wv->lkey); - - if (wv->contents) - update_submenu_strings (wv->contents); - } - } - /* Set the contents of the menubar widgets of frame F. The argument FIRST_TIME is currently ignored; --- 686,691 ----