static void keymap_panes (Lisp_Object *keymaps, ptrdiff_t nmaps) { ptrdiff_t 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, 10); finish_menu_items (); }
/* 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. */ void list_of_panes (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 (encode_menu_string (pane_name), Qnil); pane_data = Fcdr (elt); CHECK_CONS (pane_data); list_of_items (pane_data); } finish_menu_items (); }
void set_frame_menubar (struct frame *f, bool first_time, bool deep_p) { HMENU menubar_widget = f->output_data.w32->menubar_widget; Lisp_Object items; widget_value *wv, *first_wv, *prev_wv = 0; int i, last_i; int *submenu_start, *submenu_end; int *submenu_top_level_items, *submenu_n_panes; /* We must not change the menubar when actually in use. */ if (f->output_data.w32->menubar_active) return; XSETFRAME (Vmenu_updating_frame, f); if (! menubar_widget) deep_p = true; if (deep_p) { /* Make a widget-value tree representing the entire menu trees. */ struct buffer *prev = current_buffer; Lisp_Object buffer; ptrdiff_t specpdl_count = SPECPDL_INDEX (); int previous_menu_items_used = f->menu_bar_items_used; Lisp_Object *previous_items = (Lisp_Object *) alloca (previous_menu_items_used * word_size); /* If we are making a new widget, its contents are empty, do always reinitialize them. */ if (! menubar_widget) previous_menu_items_used = 0; buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents; specbind (Qinhibit_quit, Qt); /* Don't let the debugger step into this code because it is not reentrant. */ specbind (Qdebug_on_next_call, Qnil); record_unwind_save_match_data (); if (NILP (Voverriding_local_map_menu_flag)) { specbind (Qoverriding_terminal_local_map, Qnil); specbind (Qoverriding_local_map, Qnil); } set_buffer_internal_1 (XBUFFER (buffer)); /* Run the hooks. */ safe_run_hooks (Qactivate_menubar_hook); safe_run_hooks (Qmenu_bar_update_hook); fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f))); items = FRAME_MENU_BAR_ITEMS (f); /* Save the frame's previous menu bar contents data. */ if (previous_menu_items_used) memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents, previous_menu_items_used * word_size); /* 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 (ASIZE (items) * sizeof (int)); submenu_end = (int *) alloca (ASIZE (items) * sizeof (int)); submenu_n_panes = (int *) alloca (ASIZE (items) * sizeof (int)); submenu_top_level_items = (int *) alloca (ASIZE (items) * sizeof (int)); init_menu_items (); for (i = 0; i < ASIZE (items); i += 4) { Lisp_Object key, string, maps; last_i = i; key = AREF (items, i); string = AREF (items, i + 1); maps = AREF (items, i + 2); if (NILP (string)) break; submenu_start[i] = menu_items_used; menu_items_n_panes = 0; submenu_top_level_items[i] = parse_single_submenu (key, string, maps); submenu_n_panes[i] = menu_items_n_panes; submenu_end[i] = menu_items_used; } finish_menu_items (); /* Convert menu_items into widget_value trees to display the menu. This cannot evaluate Lisp code. */ wv = make_widget_value ("menubar", NULL, true, Qnil); wv->button_type = BUTTON_TYPE_NONE; first_wv = wv; for (i = 0; i < last_i; i += 4) { menu_items_n_panes = submenu_n_panes[i]; wv = digest_single_submenu (submenu_start[i], submenu_end[i], submenu_top_level_items[i]); if (prev_wv) prev_wv->next = wv; else first_wv->contents = wv; /* Don't set wv->name here; GC during the loop might relocate it. */ wv->enabled = true; wv->button_type = BUTTON_TYPE_NONE; prev_wv = wv; } set_buffer_internal_1 (prev); /* If there has been no change in the Lisp-level contents of the menu bar, skip redisplaying it. Just exit. */ 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) { free_menubar_widget_value_tree (first_wv); discard_menu_items (); unbind_to (specpdl_count, Qnil); return; } fset_menu_bar_vector (f, 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. 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 = SSDATA (string); update_submenu_strings (wv->contents); wv = wv->next; } } else { /* Make a widget-value tree containing just the top level menu bar strings. */ wv = make_widget_value ("menubar", NULL, true, Qnil); wv->button_type = BUTTON_TYPE_NONE; first_wv = wv; 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 = make_widget_value (SSDATA (string), NULL, true, Qnil); wv->button_type = BUTTON_TYPE_NONE; /* This prevents lwlib from assuming this menu item is really supposed to be empty. */ /* The EMACS_INT cast avoids a warning. This value just has to be different from small integers. */ wv->call_data = (void *) (EMACS_INT) (-1); if (prev_wv) prev_wv->next = wv; else first_wv->contents = wv; prev_wv = wv; } /* Forget what we thought we knew about what is in the detailed contents of the menu bar menus. Changing the top level always destroys the contents. */ f->menu_bar_items_used = 0; } /* Create or update the menu bar widget. */ block_input (); if (menubar_widget) { /* Empty current menubar, rather than creating a fresh one. */ while (DeleteMenu (menubar_widget, 0, MF_BYPOSITION)) ; } else { menubar_widget = CreateMenu (); } fill_in_menu (menubar_widget, first_wv->contents); free_menubar_widget_value_tree (first_wv); { HMENU old_widget = f->output_data.w32->menubar_widget; f->output_data.w32->menubar_widget = menubar_widget; SetMenu (FRAME_W32_WINDOW (f), f->output_data.w32->menubar_widget); /* Causes flicker when menu bar is updated DrawMenuBar (FRAME_W32_WINDOW (f)); */ /* Force the window size to be recomputed so that the frame's text area remains the same, if menubar has just been created. */ if (old_widget == NULL) { windows_or_buffers_changed = 23; adjust_frame_size (f, -1, -1, 2, false, Qmenu_bar_lines); } } unblock_input (); }