X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/4abe21a973ed11ed9f4ce282de8269769413c0db..b892d3c9b2ac6306b7ccdfd5bc02a84f6e43ed6c:/src/w32menu.c diff --git a/src/w32menu.c b/src/w32menu.c index a2936bc8e4..677de1b180 100644 --- a/src/w32menu.c +++ b/src/w32menu.c @@ -1,6 +1,6 @@ /* Menu support for GNU Emacs on the Microsoft W32 API. Copyright (C) 1986, 1988, 1993, 1994, 1996, 1998, 1999, 2001, 2002, - 2003, 2004, 2005, 2006, 2007, 2008 + 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -103,9 +103,6 @@ static Lisp_Object w32_menu_show P_ ((FRAME_PTR, int, int, int, int, 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. @@ -345,6 +342,7 @@ cached information about equivalent key sequences. */) if (NILP (position)) { discard_menu_items (); + FRAME_X_DISPLAY_INFO (f)->grabbed = 0; UNGCPRO; return Qnil; } @@ -358,6 +356,7 @@ cached information about equivalent key sequences. */) if (current_popup_menu) { discard_menu_items (); + FRAME_X_DISPLAY_INFO (f)->grabbed = 0; UNGCPRO; return Qnil; } @@ -370,6 +369,7 @@ cached information about equivalent key sequences. */) UNBLOCK_INPUT; discard_menu_items (); + FRAME_X_DISPLAY_INFO (f)->grabbed = 0; #endif /* HAVE_MENUS */ @@ -498,6 +498,7 @@ otherwise it is "Question". */) UNBLOCK_INPUT; discard_menu_items (); + FRAME_X_DISPLAY_INFO (f)->grabbed = 0; if (error_name) error (error_name); return selection; @@ -622,186 +623,6 @@ menubar_selection_callback (FRAME_PTR f, void * client_data) f->output_data.w32->menubar_active = 0; } - -/* 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; -} - - /* Set the contents of the menubar widgets of frame F. The argument FIRST_TIME is currently ignored; @@ -882,6 +703,8 @@ set_frame_menubar (f, first_time, deep_p) /* Fill in menu_items with the current menu bar contents. This can evaluate Lisp code. */ + save_menu_items (); + menu_items = f->menu_bar_vector; menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0; submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *)); @@ -941,7 +764,6 @@ set_frame_menubar (f, first_time, deep_p) } set_buffer_internal_1 (prev); - unbind_to (specpdl_count, Qnil); /* If there has been no change in the Lisp-level contents of the menu bar, skip redisplaying it. Just exit. */ @@ -953,11 +775,17 @@ set_frame_menubar (f, first_time, deep_p) if (i == menu_items_used && i == previous_menu_items_used && i != 0) { free_menubar_widget_value_tree (first_wv); - menu_items = Qnil; - + discard_menu_items (); + unbind_to (specpdl_count, Qnil); return; } + f->menu_bar_vector = menu_items; + f->menu_bar_items_used = menu_items_used; + + /* This undoes save_menu_items. */ + unbind_to (specpdl_count, Qnil); + /* Now GC cannot happen during the lifetime of the widget_value, so it's safe to store data from a Lisp_String, as long as local copies are made when the actual menu is created. @@ -974,10 +802,6 @@ set_frame_menubar (f, first_time, deep_p) update_submenu_strings (wv->contents); wv = wv->next; } - - f->menu_bar_vector = menu_items; - f->menu_bar_items_used = menu_items_used; - menu_items = Qnil; } else { @@ -1135,6 +959,9 @@ w32_menu_show (f, x, y, for_click, keymaps, title, error) *error = NULL; + if (menu_items_n_panes == 0) + return Qnil; + if (menu_items_used <= MENU_ITEMS_PANE_LENGTH) { *error = "Empty menu"; @@ -1284,6 +1111,7 @@ w32_menu_show (f, x, y, for_click, keymaps, title, error) abort (); wv->selected = !NILP (selected); + if (!STRINGP (help)) help = Qnil; @@ -1321,6 +1149,9 @@ w32_menu_show (f, x, y, for_click, keymaps, title, error) first_wv->contents = wv_title; } + /* No selection has been chosen yet. */ + menu_item_selection = 0; + /* Actually create the menu. */ current_popup_menu = menu = CreatePopupMenu (); fill_in_menu (menu, first_wv->contents); @@ -1330,9 +1161,6 @@ w32_menu_show (f, x, y, for_click, keymaps, title, error) pos.y = y; ClientToScreen (FRAME_W32_WINDOW (f), &pos); - /* No selection has been chosen yet. */ - menu_item_selection = 0; - /* Display the menu. */ menu_item_selection = SendMessage (FRAME_W32_WINDOW (f), WM_EMACS_TRACKPOPUPMENU, @@ -1341,6 +1169,7 @@ w32_menu_show (f, x, y, for_click, keymaps, title, error) /* Clean up extraneous mouse events which might have been generated during the call. */ discard_mouse_events (); + FRAME_X_DISPLAY_INFO (f)->grabbed = 0; /* Free the widget_value objects we used to specify the contents. */ free_menubar_widget_value_tree (first_wv); @@ -1434,7 +1263,7 @@ w32_menu_show (f, x, y, for_click, keymaps, title, error) complicated than simple yes/no type questions for which we can use the MessageBox function. */ - + static char * button_names [] = { "button1", "button2", "button3", "button4", "button5", "button6", "button7", "button8", "button9", "button10" }; @@ -2135,8 +1964,6 @@ DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_ void syms_of_w32menu () { globals_of_w32menu (); - staticpro (&menu_items); - menu_items = Qnil; current_popup_menu = NULL;