From mboxrd@z Thu Jan 1 00:00:00 1970 Path: main.gmane.org!not-for-mail From: David Ponce Newsgroups: gmane.emacs.devel Subject: Re: NT Emacs crashes when selecting a menubar item Date: Sun, 28 Jul 2002 18:56:55 +0200 Sender: emacs-devel-admin@gnu.org Message-ID: <3D442257.8000602@dponce.com> References: <3D3EF831.3040008@dponce.com> <200207251807.g6PI7I907645@aztec.santafe.edu> <3D4140EF.4000607@dponce.com> <200207271852.g6RIqmA10723@aztec.santafe.edu> NNTP-Posting-Host: localhost.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------000205050504060407060705" X-Trace: main.gmane.org 1027875489 19373 127.0.0.1 (28 Jul 2002 16:58:09 GMT) X-Complaints-To: usenet@main.gmane.org NNTP-Posting-Date: Sun, 28 Jul 2002 16:58:09 +0000 (UTC) Cc: emacs-devel@gnu.org Return-path: Original-Received: from quimby.gnus.org ([80.91.224.244]) by main.gmane.org with esmtp (Exim 3.33 #1 (Debian)) id 17YrMt-00052M-00 for ; Sun, 28 Jul 2002 18:58:07 +0200 Original-Received: from fencepost.gnu.org ([199.232.76.164]) by quimby.gnus.org with esmtp (Exim 3.12 #1 (Debian)) id 17Yrdc-0004SU-00 for ; Sun, 28 Jul 2002 19:15:24 +0200 Original-Received: from localhost ([127.0.0.1] helo=fencepost.gnu.org) by fencepost.gnu.org with esmtp (Exim 3.35 #1 (Debian)) id 17YrN2-0002hm-00; Sun, 28 Jul 2002 12:58:16 -0400 Original-Received: from smtp-out-4.wanadoo.fr ([193.252.19.23] helo=mel-rto4.wanadoo.fr) by fencepost.gnu.org with esmtp (Exim 3.35 #1 (Debian)) id 17YrM1-0002fv-00; Sun, 28 Jul 2002 12:57:13 -0400 Original-Received: from mel-rta10.wanadoo.fr (193.252.19.193) by mel-rto4.wanadoo.fr (6.5.007) id 3D18589F01122559; Sun, 28 Jul 2002 18:57:12 +0200 Original-Received: from dponce.com (80.9.193.116) by mel-rta10.wanadoo.fr (6.5.007) id 3D2A7916009477AB; Sun, 28 Jul 2002 18:57:12 +0200 User-Agent: Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.1b) Gecko/20020720 X-Accept-Language: fr, en-us, en Original-To: rms@gnu.org Errors-To: emacs-devel-admin@gnu.org X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.0.11 Precedence: bulk List-Help: List-Post: List-Subscribe: , List-Id: Emacs development discussions. List-Unsubscribe: , List-Archive: Xref: main.gmane.org gmane.emacs.devel:6109 X-Report-Spam: http://spam.gmane.org/gmane.emacs.devel:6109 This is a multi-part message in MIME format. --------------000205050504060407060705 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Hi Richard, >You have made significant progress, but we don't know the answer yet. > >Can you determine where that data becomes corrupted? >Is it written wrong at the start, or does it get >clobbered later on? > Thank you for your support! I worked hard to find the bug that corrupted menu strings, and I think I finally found it! In fact, after displaying memory locations of menu item strings in `widget_value' data structures, I noticed that sometimes their contents changed (not the location) between their initialization in `single_submenu' and their use in `add_menu_item'. This looked like a bad interaction with GC. I carefully reviewed the code and was first disappointed because all the Lisp strings that produced menu item strings seemed correctly protected from GC! I looked more thoroughly at the GC code, and discovered that the data part of Lisp strings may be relocated when GC compacts the Lisp string storage. Even when the base string Lisp_Object is protected! So, I hacked w32menu.c to used safe local copy of menu item strings, and the bug disappeared :-) From that base, I took time to properly update w32menu.c, and fixed another bug too, related to pop up menu cleanup. Finally I cleaned up the code to generalize use of AREF, ASET and ASIZE macros. Attached you will find the patch, the change log is at end. With the patch menus work very well now, with no noticeable slow down (I used the faster Win32 API to alloc/free memory). I don't know if it is possible, or if that could solve such problems (is it guaranteed that GC can't raise when a menu is showing up?), but perhaps a more general solution, probably with more impact, would be to directly use Lisp strings in `widget_value', like for help items? What do you think? Sincerely, David ------------------------ Change Log -------------------------------- (local_heap, local_alloc, local_free): New macros. (malloc_widget_value, free_widget_value) (free_menubar_widget_value_tree) (w32_free_submenu_strings): Use them. (local-string): New function. (single_submenu, set_frame_menubar) (w32_menu_show, add_menu_item): Use it. (push_submenu_start, push_submenu_end, push_left_right_boundary) (push_menu_pane, push_menu_item, single_keymap_panes) (single_menu_item, Fx_popup_menu, menubar_selection_callback) (single_submenu, set_frame_menubar) (w32_menu_show, w32_dialog_show): Use AREF, ASET, ASIZE. (Fx_popup_menu): Don't show pop up menu until preceding one is actually cleaned up. Moved UNGCPRO outside #ifdef HAVE_MENUS block. --------------000205050504060407060705 Content-Type: text/x-patch; name="w32menu.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="w32menu.patch" *** w32menu.c.ori Mon Jul 15 10:48:32 2002 --- w32menu.c Sun Jul 28 18:35:13 2002 *************** *** 112,120 **** #endif } widget_value; ! /* LocalAlloc/Free is a reasonably good allocator. */ ! #define malloc_widget_value() (void*)LocalAlloc (LMEM_ZEROINIT, sizeof (widget_value)) ! #define free_widget_value(wv) LocalFree (wv) /******************************************************************/ --- 112,124 ---- #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))) /******************************************************************/ *************** *** 318,324 **** if (menu_items_used + 1 > menu_items_allocated) grow_menu_items (); ! XVECTOR (menu_items)->contents[menu_items_used++] = Qnil; menu_items_submenu_depth++; } --- 322,328 ---- if (menu_items_used + 1 > menu_items_allocated) grow_menu_items (); ! ASET (menu_items, menu_items_used++, Qnil); menu_items_submenu_depth++; } *************** *** 330,336 **** if (menu_items_used + 1 > menu_items_allocated) grow_menu_items (); ! XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda; menu_items_submenu_depth--; } --- 334,340 ---- if (menu_items_used + 1 > menu_items_allocated) grow_menu_items (); ! ASET (menu_items, menu_items_used++, Qlambda); menu_items_submenu_depth--; } *************** *** 342,348 **** if (menu_items_used + 1 > menu_items_allocated) grow_menu_items (); ! XVECTOR (menu_items)->contents[menu_items_used++] = Qquote; } /* Start a new menu pane in menu_items. --- 346,352 ---- if (menu_items_used + 1 > menu_items_allocated) grow_menu_items (); ! ASET (menu_items, menu_items_used++, Qquote); } /* Start a new menu pane in menu_items. *************** *** 357,365 **** if (menu_items_submenu_depth == 0) menu_items_n_panes++; ! XVECTOR (menu_items)->contents[menu_items_used++] = Qt; ! XVECTOR (menu_items)->contents[menu_items_used++] = name; ! XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec; } /* Push one menu item into the current pane. NAME is the string to --- 361,369 ---- if (menu_items_submenu_depth == 0) menu_items_n_panes++; ! ASET (menu_items, menu_items_used++, Qt); ! ASET (menu_items, menu_items_used++, name); ! ASET (menu_items, menu_items_used++, prefix_vec); } /* Push one menu item into the current pane. NAME is the string to *************** *** 377,390 **** if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated) grow_menu_items (); ! XVECTOR (menu_items)->contents[menu_items_used++] = name; ! XVECTOR (menu_items)->contents[menu_items_used++] = enable; ! XVECTOR (menu_items)->contents[menu_items_used++] = key; ! XVECTOR (menu_items)->contents[menu_items_used++] = equiv; ! XVECTOR (menu_items)->contents[menu_items_used++] = def; ! XVECTOR (menu_items)->contents[menu_items_used++] = type; ! XVECTOR (menu_items)->contents[menu_items_used++] = selected; ! XVECTOR (menu_items)->contents[menu_items_used++] = help; } /* Look through KEYMAPS, a vector of keymaps that is NMAPS long, --- 381,394 ---- if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated) grow_menu_items (); ! ASET (menu_items, menu_items_used++, name); ! ASET (menu_items, menu_items_used++, enable); ! ASET (menu_items, menu_items_used++, key); ! ASET (menu_items, menu_items_used++, equiv); ! ASET (menu_items, menu_items_used++, def); ! ASET (menu_items, menu_items_used++, type); ! ASET (menu_items, menu_items_used++, selected); ! ASET (menu_items, menu_items_used++, help); } /* Look through KEYMAPS, a vector of keymaps that is NMAPS long, *************** *** 450,462 **** else if (VECTORP (item)) { /* Loop over the char values represented in the vector. */ ! int len = XVECTOR (item)->size; int c; for (c = 0; c < len; c++) { Lisp_Object character; XSETFASTINT (character, c); ! single_menu_item (character, XVECTOR (item)->contents[c], &pending_maps, notreal, maxdepth); } } --- 454,466 ---- 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); } } *************** *** 504,510 **** if (!res) return; /* Not a menu item. */ ! map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP]; if (notreal) { --- 508,514 ---- if (!res) return; /* Not a menu item. */ ! map = AREF (item_properties, ITEM_PROPERTY_MAP); if (notreal) { *************** *** 515,522 **** return; } ! enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE]; ! item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME]; if (!NILP (map) && SREF (item_string, 0) == '@') { --- 519,526 ---- return; } ! enabled = AREF (item_properties, ITEM_PROPERTY_ENABLE); ! item_string = AREF (item_properties, ITEM_PROPERTY_NAME); if (!NILP (map) && SREF (item_string, 0) == '@') { *************** *** 528,538 **** } push_menu_item (item_string, enabled, key, ! XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF], ! XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ], ! XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE], ! XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED], ! XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]); /* Display a submenu using the toolkit. */ if (! (NILP (map) || NILP (enabled))) --- 532,542 ---- } push_menu_item (item_string, enabled, key, ! AREF (item_properties, ITEM_PROPERTY_DEF), ! AREF (item_properties, ITEM_PROPERTY_KEYEQ), ! AREF (item_properties, ITEM_PROPERTY_TYPE), ! AREF (item_properties, ITEM_PROPERTY_SELECTED), ! AREF (item_properties, ITEM_PROPERTY_HELP)); /* Display a submenu using the toolkit. */ if (! (NILP (map) || NILP (enabled))) *************** *** 745,751 **** /* Make that be the pane title of the first pane. */ if (!NILP (prompt) && menu_items_n_panes >= 0) ! XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = prompt; keymaps = 1; } --- 749,755 ---- /* Make that be the pane title of the first pane. */ if (!NILP (prompt) && menu_items_n_panes >= 0) ! ASET (menu_items, MENU_ITEMS_PANE_NAME, prompt); keymaps = 1; } *************** *** 777,783 **** /* Make the title be the pane title of the first pane. */ if (!NILP (title) && menu_items_n_panes >= 0) ! XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title; keymaps = 1; } --- 781,787 ---- /* Make the title be the pane title of the first pane. */ if (!NILP (title) && menu_items_n_panes >= 0) ! ASET (menu_items, MENU_ITEMS_PANE_NAME, title); keymaps = 1; } *************** *** 800,805 **** --- 804,819 ---- } #ifdef HAVE_MENUS + /* If resources from a previous popup menu exist yet, does nothing + until the `menu_free_timer' has freed them (see w32fns.c). + */ + if (current_popup_menu) + { + discard_menu_items (); + UNGCPRO; + return Qnil; + } + /* Display them in a menu. */ BLOCK_INPUT; *************** *** 808,816 **** UNBLOCK_INPUT; discard_menu_items (); UNGCPRO; - #endif /* HAVE_MENUS */ if (error_name) error (error_name); return selection; --- 822,830 ---- UNBLOCK_INPUT; discard_menu_items (); + #endif /* HAVE_MENUS */ UNGCPRO; if (error_name) error (error_name); return selection; *************** *** 981,1005 **** i = 0; while (i < f->menu_bar_items_used) { ! if (EQ (XVECTOR (vector)->contents[i], Qnil)) { subprefix_stack[submenu_depth++] = prefix; prefix = entry; i++; } ! else if (EQ (XVECTOR (vector)->contents[i], Qlambda)) { prefix = subprefix_stack[--submenu_depth]; i++; } ! else if (EQ (XVECTOR (vector)->contents[i], Qt)) { ! prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX]; i += MENU_ITEMS_PANE_LENGTH; } else { ! entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE]; /* The EMACS_INT cast avoids a warning. There's no problem as long as pointers have enough bits to hold small integers. */ if ((int) (EMACS_INT) client_data == i) --- 995,1019 ---- i = 0; while (i < f->menu_bar_items_used) { ! if (EQ (AREF (vector, i), Qnil)) { subprefix_stack[submenu_depth++] = prefix; prefix = entry; i++; } ! else if (EQ (AREF (vector, i), Qlambda)) { prefix = subprefix_stack[--submenu_depth]; i++; } ! else if (EQ (AREF (vector, i), Qt)) { ! prefix = AREF (vector, i + MENU_ITEMS_PANE_PREFIX); i += MENU_ITEMS_PANE_LENGTH; } else { ! entry = AREF (vector, i + MENU_ITEMS_ITEM_VALUE); /* The EMACS_INT cast avoids a warning. There's no problem as long as pointers have enough bits to hold small integers. */ if ((int) (EMACS_INT) client_data == i) *************** *** 1051,1056 **** --- 1065,1089 ---- f->output_data.w32->menubar_active = 0; } + /* Return a local copy of the given input string STR. + Does nothing if STR is 0. + + It is necessary to use safe local copy of string data stored in + widget_value because the data part of Lisp strings can be relocated + when the GC compacts string storage. Even when the base string + Lisp_Object is protected! */ + char * + local_string (const char *str) + { + if (str) + { + char *clone = (char *) local_alloc (strlen (str) + 1); + strcpy (clone, str); + return clone; + } + return 0; + } + /* Allocate a widget_value, blocking input. */ widget_value * *************** *** 1075,1081 **** widget_value *wv; { if (! wv) return; ! wv->name = wv->value = wv->key = (char *) 0xDEADBEEF; if (wv->contents && (wv->contents != (widget_value*)1)) --- 1108,1118 ---- widget_value *wv; { if (! wv) return; ! ! local_free (wv->name); ! local_free (wv->value); ! local_free (wv->key); ! wv->name = wv->value = wv->key = (char *) 0xDEADBEEF; if (wv->contents && (wv->contents != (widget_value*)1)) *************** *** 1148,1154 **** 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; --- 1185,1191 ---- submenu_stack = (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); wv = xmalloc_widget_value (); ! wv->name = local_string ("menu"); wv->value = 0; wv->enabled = 1; wv->button_type = BUTTON_TYPE_NONE; *************** *** 1164,1203 **** i = previous_items; while (i < menu_items_used) { ! if (EQ (XVECTOR (menu_items)->contents[i], Qnil)) { submenu_stack[submenu_depth++] = save_wv; save_wv = prev_wv; prev_wv = 0; i++; } ! else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda)) { prev_wv = save_wv; save_wv = submenu_stack[--submenu_depth]; i++; } ! else if (EQ (XVECTOR (menu_items)->contents[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 (XVECTOR (menu_items)->contents[i], Qquote)) i += 1; ! else if (EQ (XVECTOR (menu_items)->contents[i], Qt)) { /* Create a new pane. */ Lisp_Object pane_name, prefix; char *pane_string; ! pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME]; ! prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; #ifndef HAVE_MULTILINGUAL_MENU if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) { pane_name = ENCODE_SYSTEM (pane_name); ! AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name; } #endif pane_string = (NILP (pane_name) --- 1201,1240 ---- i = previous_items; while (i < menu_items_used) { ! 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); #ifndef HAVE_MULTILINGUAL_MENU if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) { pane_name = ENCODE_SYSTEM (pane_name); ! ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name); } #endif pane_string = (NILP (pane_name) *************** *** 1222,1227 **** --- 1259,1265 ---- This is a kludge, but this isn't worth more time. */ if (!NILP (prefix) && wv->name[0] == '@') wv->name++; + wv->name = local_string (wv->name); wv->value = 0; wv->enabled = 1; wv->button_type = BUTTON_TYPE_NONE; *************** *** 1249,1261 **** if (STRING_MULTIBYTE (item_name)) { item_name = ENCODE_SYSTEM (item_name); ! AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name; } if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) { descrip = ENCODE_SYSTEM (descrip); ! AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip; } #endif /* not HAVE_MULTILINGUAL_MENU */ --- 1287,1299 ---- 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); } #endif /* not HAVE_MULTILINGUAL_MENU */ *************** *** 1265,1273 **** else save_wv->contents = wv; ! wv->name = (char *) SDATA (item_name); if (!NILP (descrip)) ! wv->key = (char *) SDATA (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. */ --- 1303,1311 ---- else save_wv->contents = wv; ! wv->name = local_string ((char *) SDATA (item_name)); if (!NILP (descrip)) ! wv->key = local_string ((char *) SDATA (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. */ *************** *** 1334,1340 **** deep_p = 1; wv = xmalloc_widget_value (); ! wv->name = "menubar"; wv->value = 0; wv->enabled = 1; wv->button_type = BUTTON_TYPE_NONE; --- 1372,1378 ---- deep_p = 1; wv = xmalloc_widget_value (); ! wv->name = local_string ("menubar"); wv->value = 0; wv->enabled = 1; wv->button_type = BUTTON_TYPE_NONE; *************** *** 1395,1407 **** menu_items = f->menu_bar_vector; menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0; init_menu_items (); ! for (i = 0; i < XVECTOR (items)->size; i += 4) { Lisp_Object key, string, maps; ! key = XVECTOR (items)->contents[i]; ! string = XVECTOR (items)->contents[i + 1]; ! maps = XVECTOR (items)->contents[i + 2]; if (NILP (string)) break; --- 1433,1445 ---- menu_items = f->menu_bar_vector; menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0; init_menu_items (); ! for (i = 0; i < ASIZE (items); i += 4) { Lisp_Object key, string, maps; ! key = AREF (items, i); ! string = AREF (items, i + 1); ! maps = AREF (items, i + 2); if (NILP (string)) break; *************** *** 1426,1432 **** for (i = 0; i < previous_menu_items_used; i++) if (menu_items_used == i ! || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i]))) break; if (i == menu_items_used && i == previous_menu_items_used && i != 0) { --- 1464,1470 ---- for (i = 0; i < previous_menu_items_used; i++) if (menu_items_used == i ! || (!EQ (previous_items[i], AREF (menu_items, i)))) break; if (i == menu_items_used && i == previous_menu_items_used && i != 0) { *************** *** 1442,1454 **** Windows takes care of this for normal string items, but not for owner-drawn items or additional item-info. */ wv = first_wv->contents; ! for (i = 0; i < XVECTOR (items)->size; i += 4) { Lisp_Object string; ! string = XVECTOR (items)->contents[i + 1]; if (NILP (string)) break; ! wv->name = (char *) SDATA (string); wv = wv->next; } --- 1480,1492 ---- Windows takes care of this for normal string items, but not for owner-drawn items or additional item-info. */ wv = first_wv->contents; ! for (i = 0; i < ASIZE (items); i += 4) { Lisp_Object string; ! string = AREF (items, i + 1); if (NILP (string)) break; ! wv->name = local_string ((char *) SDATA (string)); wv = wv->next; } *************** *** 1462,1477 **** just the top level menu bar strings. */ items = FRAME_MENU_BAR_ITEMS (f); ! for (i = 0; i < XVECTOR (items)->size; i += 4) { Lisp_Object string; ! string = XVECTOR (items)->contents[i + 1]; if (NILP (string)) break; wv = xmalloc_widget_value (); ! wv->name = (char *) SDATA (string); wv->value = 0; wv->enabled = 1; wv->button_type = BUTTON_TYPE_NONE; --- 1500,1515 ---- just the top level menu bar strings. */ items = FRAME_MENU_BAR_ITEMS (f); ! for (i = 0; i < ASIZE (items); i += 4) { Lisp_Object string; ! string = AREF (items, i + 1); if (NILP (string)) break; wv = xmalloc_widget_value (); ! wv->name = local_string ((char *) SDATA (string)); wv->value = 0; wv->enabled = 1; wv->button_type = BUTTON_TYPE_NONE; *************** *** 1613,1619 **** /* Create a tree of widget_value objects representing the panes and their items. */ wv = xmalloc_widget_value (); ! wv->name = "menu"; wv->value = 0; wv->enabled = 1; wv->button_type = BUTTON_TYPE_NONE; --- 1651,1657 ---- /* Create a tree of widget_value objects representing the panes and their items. */ wv = xmalloc_widget_value (); ! wv->name = local_string ("menu"); wv->value = 0; wv->enabled = 1; wv->button_type = BUTTON_TYPE_NONE; *************** *** 1625,1631 **** i = 0; while (i < menu_items_used) { ! if (EQ (XVECTOR (menu_items)->contents[i], Qnil)) { submenu_stack[submenu_depth++] = save_wv; save_wv = prev_wv; --- 1663,1669 ---- i = 0; while (i < menu_items_used) { ! if (EQ (AREF (menu_items, i), Qnil)) { submenu_stack[submenu_depth++] = save_wv; save_wv = prev_wv; *************** *** 1633,1653 **** first_pane = 1; i++; } ! else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda)) { prev_wv = save_wv; save_wv = submenu_stack[--submenu_depth]; first_pane = 0; i++; } ! else if (EQ (XVECTOR (menu_items)->contents[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 (XVECTOR (menu_items)->contents[i], Qquote)) i += 1; ! else if (EQ (XVECTOR (menu_items)->contents[i], Qt)) { /* Create a new pane. */ Lisp_Object pane_name, prefix; --- 1671,1691 ---- first_pane = 1; i++; } ! else if (EQ (AREF (menu_items, i), Qlambda)) { prev_wv = save_wv; save_wv = submenu_stack[--submenu_depth]; first_pane = 0; 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; *************** *** 1658,1664 **** if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) { pane_name = ENCODE_SYSTEM (pane_name); ! AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name; } #endif pane_string = (NILP (pane_name) --- 1696,1702 ---- if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) { pane_name = ENCODE_SYSTEM (pane_name); ! ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name); } #endif pane_string = (NILP (pane_name) *************** *** 1681,1686 **** --- 1719,1725 ---- wv->name = pane_string; if (keymaps && !NILP (prefix)) wv->name++; + wv->name = local_string (wv->name); wv->value = 0; wv->enabled = 1; wv->button_type = BUTTON_TYPE_NONE; *************** *** 1713,1724 **** if (STRINGP (item_name) && STRING_MULTIBYTE (item_name)) { item_name = ENCODE_SYSTEM (item_name); ! AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name; } if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) { descrip = ENCODE_SYSTEM (descrip); ! AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip; } #endif /* not HAVE_MULTILINGUAL_MENU */ --- 1752,1763 ---- if (STRINGP (item_name) && 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); } #endif /* not HAVE_MULTILINGUAL_MENU */ *************** *** 1727,1735 **** prev_wv->next = wv; else save_wv->contents = wv; ! wv->name = (char *) SDATA (item_name); if (!NILP (descrip)) ! wv->key = (char *) SDATA (descrip); wv->value = 0; /* Use the contents index as call_data, since we are restricted to 16-bits. */ --- 1766,1774 ---- prev_wv->next = wv; else save_wv->contents = wv; ! wv->name = local_string ((char *) SDATA (item_name)); if (!NILP (descrip)) ! wv->key = local_string ((char *) SDATA (descrip)); wv->value = 0; /* Use the contents index as call_data, since we are restricted to 16-bits. */ *************** *** 1765,1771 **** /* Maybe replace this separator with a bitmap or owner-draw item so that it looks better. Having two separators looks odd. */ ! wv_sep->name = "--"; wv_sep->next = first_wv->contents; wv_sep->help = Qnil; --- 1804,1810 ---- /* Maybe replace this separator with a bitmap or owner-draw item so that it looks better. Having two separators looks odd. */ ! wv_sep->name = local_string ("--"); wv_sep->next = first_wv->contents; wv_sep->help = Qnil; *************** *** 1773,1779 **** if (STRING_MULTIBYTE (title)) title = ENCODE_SYSTEM (title); #endif ! wv_title->name = (char *) SDATA (title); wv_title->enabled = TRUE; wv_title->title = TRUE; wv_title->button_type = BUTTON_TYPE_NONE; --- 1812,1818 ---- if (STRING_MULTIBYTE (title)) title = ENCODE_SYSTEM (title); #endif ! wv_title->name = local_string ((char *) SDATA (title)); wv_title->enabled = TRUE; wv_title->title = TRUE; wv_title->button_type = BUTTON_TYPE_NONE; *************** *** 1818,1848 **** i = 0; while (i < menu_items_used) { ! if (EQ (XVECTOR (menu_items)->contents[i], Qnil)) { subprefix_stack[submenu_depth++] = prefix; prefix = entry; i++; } ! else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda)) { prefix = subprefix_stack[--submenu_depth]; i++; } ! else if (EQ (XVECTOR (menu_items)->contents[i], Qt)) { ! prefix ! = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; i += MENU_ITEMS_PANE_LENGTH; } /* Ignore a nil in the item list. It's meaningful only for dialog boxes. */ ! else if (EQ (XVECTOR (menu_items)->contents[i], Qquote)) i += 1; else { ! entry ! = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE]; if (menu_item_selection == i) { if (keymaps != 0) --- 1857,1885 ---- i = 0; while (i < menu_items_used) { ! if (EQ (AREF (menu_items, i), Qnil)) { subprefix_stack[submenu_depth++] = prefix; prefix = entry; i++; } ! else if (EQ (AREF (menu_items, i), Qlambda)) { prefix = subprefix_stack[--submenu_depth]; i++; } ! else if (EQ (AREF (menu_items, i), Qt)) { ! prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); 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 { ! entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE); if (menu_item_selection == i) { if (keymaps != 0) *************** *** 1903,1910 **** { Lisp_Object pane_name, prefix; char *pane_string; ! pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME]; ! prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX]; pane_string = (NILP (pane_name) ? "" : (char *) SDATA (pane_name)); prev_wv = xmalloc_widget_value (); --- 1940,1947 ---- { Lisp_Object pane_name, prefix; char *pane_string; ! pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME); ! prefix = AREF (menu_items, MENU_ITEMS_PANE_PREFIX); pane_string = (NILP (pane_name) ? "" : (char *) SDATA (pane_name)); prev_wv = xmalloc_widget_value (); *************** *** 1924,1934 **** /* Create a new item within current pane. */ Lisp_Object item_name, enable, descrip, help; ! item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME]; ! enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE]; ! descrip ! = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY]; ! help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP]; if (NILP (item_name)) { --- 1961,1970 ---- /* Create a new item within current pane. */ Lisp_Object item_name, enable, descrip, 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); ! help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP); if (NILP (item_name)) { *************** *** 1957,1963 **** if (!NILP (descrip)) wv->key = (char *) SDATA (descrip); wv->value = (char *) SDATA (item_name); ! wv->call_data = (void *) &XVECTOR (menu_items)->contents[i]; wv->enabled = !NILP (enable); wv->help = Qnil; prev_wv = wv; --- 1993,1999 ---- if (!NILP (descrip)) wv->key = (char *) SDATA (descrip); wv->value = (char *) SDATA (item_name); ! wv->call_data = (void *) &AREF (menu_items, i); wv->enabled = !NILP (enable); wv->help = Qnil; prev_wv = wv; *************** *** 2027,2042 **** { Lisp_Object entry; ! if (EQ (XVECTOR (menu_items)->contents[i], Qt)) { ! prefix ! = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; i += MENU_ITEMS_PANE_LENGTH; } else { ! entry ! = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE]; if (menu_item_selection == i) { if (keymaps != 0) --- 2063,2076 ---- { Lisp_Object entry; ! if (EQ (AREF (menu_items, i), Qt)) { ! prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); i += MENU_ITEMS_PANE_LENGTH; } else { ! entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE); if (menu_item_selection == i) { if (keymaps != 0) *************** *** 2117,2127 **** we can't deallocate the memory otherwise. */ if (get_menu_item_info) { ! out_string = (char *) LocalAlloc (LPTR, strlen (wv->name) + 1); #ifdef MENU_DEBUG ! DebPrint ("Menu: allocing %ld for owner-draw", info.dwItemData); #endif - strcpy (out_string, wv->name); fuFlags = MF_OWNERDRAW | MF_DISABLED; } else --- 2151,2160 ---- we can't deallocate the memory otherwise. */ if (get_menu_item_info) { ! out_string = local_string (wv->name); #ifdef MENU_DEBUG ! DebPrint ("Menu: allocing %ld for owner-draw", out_string); #endif fuFlags = MF_OWNERDRAW | MF_DISABLED; } else *************** *** 2277,2283 **** #ifdef MENU_DEBUG DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData); #endif ! LocalFree (info.dwItemData); } /* Recurse down submenus. */ --- 2310,2316 ---- #ifdef MENU_DEBUG DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData); #endif ! local_free (info.dwItemData); } /* Recurse down submenus. */ --------------000205050504060407060705--