From 88766961a3fba6124141677864ea248359729a13 Mon Sep 17 00:00:00 2001 From: "Richard M. Stallman" Date: Tue, 25 Jul 1995 20:26:10 +0000 Subject: [PATCH] Include buffer.h. (x_activate_menubar): New function. (set_frame_menubar): New arg deep_p. Callers changed. Run various hooks here when deep_p is true. (frame_vector): Variable deleted. (syms_of_xmenu): Don't staticpro it. (frame_vector_add_frame): Function deleted. (menubar_id_to_frame): New function. (menubar_selection_callback): Use menubar_id_to_frame. (next_menubar_widget_id): New variable. (set_frame_menubar): Use next_menubar_widget_id. (free_frame_menubar): Get id from f->display.x->id. --- src/xmenu.c | 316 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 198 insertions(+), 118 deletions(-) diff --git a/src/xmenu.c b/src/xmenu.c index c0574fe0779..7821f9987d5 100644 --- a/src/xmenu.c +++ b/src/xmenu.c @@ -41,6 +41,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "keyboard.h" #include "blockinput.h" #include "puresize.h" +#include "buffer.h" #ifdef MSDOS #include "msdos.h" @@ -90,7 +91,15 @@ extern Lisp_Object Qmouse_click, Qevent_kind; extern Lisp_Object Vdefine_key_rebound_commands; +extern Lisp_Object Voverriding_local_map; +extern Lisp_Object Voverriding_local_map_menu_flag; + +extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map; + +extern Lisp_Object Qmenu_bar_update_hook; + #ifdef USE_X_TOOLKIT +extern void set_frame_menubar (); extern void process_expose_from_menu (); extern XtAppContext Xt_app_con; @@ -156,48 +165,34 @@ static int menu_items_submenu_depth; Xt on behalf of one of the widget sets. */ static int popup_activated_flag; -/* This holds a Lisp vector - which contains frames that have menu bars. - Each frame that has a menu bar is found at some index in this vector - and the menu bar widget refers to the frame through that index. */ -static Lisp_Object frame_vector; +static int next_menubar_widget_id; -/* Return the index of FRAME in frame_vector. - If FRAME isn't in frame_vector yet, put it in, - lengthening the vector if necessary. */ - -static int -frame_vector_add_frame (f) - FRAME_PTR *f; -{ - int length = XVECTOR (frame_vector)->size; - int i, empty = -1; - Lisp_Object new, frame; +#ifdef USE_X_TOOLKIT - XSETFRAME (frame, f); +/* Return the frame whose ->display.x->id equals ID, or 0 if none. */ - for (i = 0; i < length; i++) - { - if (EQ (frame, XVECTOR (frame_vector)->contents[i])) - return i; - if (NILP (XVECTOR (frame_vector)->contents[i])) - empty = i; - } +static struct frame * +menubar_id_to_frame (id) + LWLIB_ID id; +{ + Lisp_Object tail, frame; + FRAME_PTR f; - if (empty >= 0) + for (tail = Vframe_list; GC_CONSP (tail); tail = XCONS (tail)->cdr) { - XVECTOR (frame_vector)->contents[empty] = frame; - return empty; + frame = XCONS (tail)->car; + if (!GC_FRAMEP (frame)) + continue; + f = XFRAME (frame); + if (f->display.nothing == 1) + continue; + if (f->display.x->id == id) + return f; } - - new = Fmake_vector (make_number (length * 2), Qnil); - bcopy (XVECTOR (frame_vector)->contents, - XVECTOR (new)->contents, sizeof (Lisp_Object) * length); - - frame_vector = new; - XVECTOR (frame_vector)->contents[length] = frame; - return length; + return 0; } + +#endif /* Initialize the menu_items structure if we haven't already done so. Also mark it as currently empty. */ @@ -1139,6 +1134,36 @@ popup_get_selection (initial_event, dpyinfo, id) } } +/* Activate the menu bar of frame F. + This is called from keyboard.c when it gets the + menu_bar_activate_event out of the Emacs event queue. + + To activate the menu bar, we use the X button-press event + that was saved in saved_button_event. + That makes the toolkit do its thing. + + But first we recompute the menu bar contents (the whole tree). + + The reason for saving the button event until here, instead of + passing it to the toolkit right away, is that we can safely + execute Lisp code. */ + +x_activate_menubar (f) + FRAME_PTR f; +{ + if (f->display.x->saved_button_event->type != ButtonPress) + return; + + set_frame_menubar (f, 0, 1); + + BLOCK_INPUT; + XtDispatchEvent ((XEvent *) f->display.x->saved_button_event); + UNBLOCK_INPUT; + + /* Ignore this if we get it a second time. */ + f->display.x->saved_button_event->type = 0; +} + /* Detect if a dialog or menu has been posted. */ int @@ -1172,7 +1197,7 @@ menubar_selection_callback (widget, id, client_data) XtPointer client_data; { Lisp_Object prefix, entry; - FRAME_PTR f = XFRAME (XVECTOR (frame_vector)->contents[id]); + FRAME_PTR f = menubar_id_to_frame (id); Lisp_Object vector; Lisp_Object *subprefix_stack; int submenu_depth = 0; @@ -1513,101 +1538,163 @@ update_frame_menubar (f) it is set the first time this is called, from initialize_frame_menubar. */ void -set_frame_menubar (f, first_time) +set_frame_menubar (f, first_time, deep_p) FRAME_PTR f; int first_time; + int deep_p; { Widget menubar_widget = f->display.x->menubar_widget; Lisp_Object tail, items, frame; widget_value *wv, *first_wv, *prev_wv = 0; - int previous_menu_items_used = f->menu_bar_items_used; - Lisp_Object *previous_items - = (Lisp_Object *) alloca (previous_menu_items_used * sizeof (Lisp_Object)); int i; - int id; - int count; - int specpdl_count = specpdl_ptr - specpdl; - - count = inhibit_garbage_collection (); + LWLIB_ID id; - specbind (Qinhibit_quit, Qt); - /* Don't let the debugger step into this code - because it is not reentrant. */ - specbind (Qdebug_on_next_call, Qnil); + if (f->display.x->id == 0) + f->display.x->id = next_menubar_widget_id++; + id = f->display.x->id; - id = frame_vector_add_frame (f); + if (! menubar_widget) + deep_p = 1; wv = malloc_widget_value (); wv->name = "menubar"; wv->value = 0; wv->enabled = 1; first_wv = wv; - items = FRAME_MENU_BAR_ITEMS (f); - /* Save the frame's previous menu bar contents data. */ - bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items, - previous_menu_items_used * sizeof (Lisp_Object)); - - /* Fill in the current menu bar contents. */ - menu_items = f->menu_bar_vector; - menu_items_allocated = XVECTOR (menu_items)->size; - init_menu_items (); - for (i = 0; i < XVECTOR (items)->size; i += 3) + if (deep_p) { - Lisp_Object key, string, maps; + /* Make a widget-value tree representing the entire menu trees. */ + + struct buffer *prev = current_buffer; + Lisp_Object buffer; + int specpdl_count = specpdl_ptr - specpdl; + int previous_menu_items_used = f->menu_bar_items_used; + Lisp_Object *previous_items + = (Lisp_Object *) alloca (previous_menu_items_used + * sizeof (Lisp_Object)); + + buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer; + 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_protect (Fstore_match_data, Fmatch_data ()); + if (NILP (Voverriding_local_map_menu_flag)) + { + specbind (Qoverriding_terminal_local_map, Qnil); + specbind (Qoverriding_local_map, Qnil); + } - key = XVECTOR (items)->contents[i]; - string = XVECTOR (items)->contents[i + 1]; - maps = XVECTOR (items)->contents[i + 2]; - if (NILP (string)) - break; + set_buffer_internal_1 (XBUFFER (buffer)); - wv = single_submenu (key, string, maps); - 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 = 1; - prev_wv = wv; - } + /* Run the Lucid hook. */ + call1 (Vrun_hooks, Qactivate_menubar_hook); + /* If it has changed current-menubar from previous value, + really recompute the menubar from the value. */ + if (! NILP (Vlucid_menu_bar_dirty_flag)) + call0 (Qrecompute_lucid_menubar); + call1 (Vrun_hooks, Qmenu_bar_update_hook); + FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f)); - finish_menu_items (); + items = FRAME_MENU_BAR_ITEMS (f); - /* If there has been no change in the Lisp-level contents - of the menu bar, skip redisplaying it. Just exit. */ + inhibit_garbage_collection (); - for (i = 0; i < previous_menu_items_used; i++) - if (menu_items_used == i - || (previous_items[i] != XVECTOR (menu_items)->contents[i])) - break; - if (i == menu_items_used && i == previous_menu_items_used) - { - free_menubar_widget_value_tree (first_wv); - menu_items = Qnil; + /* Save the frame's previous menu bar contents data. */ + bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items, + previous_menu_items_used * sizeof (Lisp_Object)); + /* Fill in the current menu bar contents. */ + menu_items = f->menu_bar_vector; + menu_items_allocated = XVECTOR (menu_items)->size; + init_menu_items (); + for (i = 0; i < XVECTOR (items)->size; i += 3) + { + 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; + + wv = single_submenu (key, string, maps); + 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 = 1; + prev_wv = wv; + } + + finish_menu_items (); + + set_buffer_internal_1 (prev); unbind_to (specpdl_count, Qnil); - return; - } - /* Now GC cannot happen during the lifetime of the widget_value, - so it's safe to store data from a Lisp_String. */ - wv = first_wv->contents; - for (i = 0; i < XVECTOR (items)->size; i += 3) - { - Lisp_Object string; - string = XVECTOR (items)->contents[i + 1]; - if (NILP (string)) - break; - wv->name = (char *) XSTRING (string)->data; - wv = wv->next; + /* 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 + || (previous_items[i] != XVECTOR (menu_items)->contents[i])) + break; + if (i == menu_items_used && i == previous_menu_items_used) + { + free_menubar_widget_value_tree (first_wv); + menu_items = Qnil; + + return; + } + + /* Now GC cannot happen during the lifetime of the widget_value, + so it's safe to store data from a Lisp_String. */ + wv = first_wv->contents; + for (i = 0; i < XVECTOR (items)->size; i += 3) + { + Lisp_Object string; + string = XVECTOR (items)->contents[i + 1]; + if (NILP (string)) + break; + wv->name = (char *) XSTRING (string)->data; + wv = wv->next; + } + + f->menu_bar_vector = menu_items; + f->menu_bar_items_used = menu_items_used; + menu_items = Qnil; } + else + { + /* Make a widget-value tree containing + just the top level menu bar strings. */ - f->menu_bar_vector = menu_items; - f->menu_bar_items_used = menu_items_used; - menu_items = Qnil; + items = FRAME_MENU_BAR_ITEMS (f); + for (i = 0; i < XVECTOR (items)->size; i += 3) + { + Lisp_Object string; + + string = XVECTOR (items)->contents[i + 1]; + if (NILP (string)) + break; + + wv = malloc_widget_value (); + wv->name = (char *) XSTRING (string)->data; + wv->value = 0; + wv->enabled = 1; + + if (prev_wv) + prev_wv->next = wv; + else + first_wv->contents = wv; + prev_wv = wv; + } + } - unbind_to (count, Qnil); + /* Create or update the menu bar widget. */ BLOCK_INPUT; @@ -1618,15 +1705,14 @@ set_frame_menubar (f, first_time) /* The third arg is DEEP_P, which says to consider the entire menu trees we supply, rather than just the menu bar item names. */ - lw_modify_all_widgets ((LWLIB_ID) id, first_wv, 1); + lw_modify_all_widgets (id, first_wv, deep_p); /* Re-enable the edit widget to resize. */ lw_allow_resizing (f->display.x->widget, True); } else { - menubar_widget = lw_create_widget ("menubar", "menubar", - (LWLIB_ID) id, first_wv, + menubar_widget = lw_create_widget ("menubar", "menubar", id, first_wv, f->display.x->column_widget, 0, popup_activate_callback, @@ -1658,8 +1744,6 @@ set_frame_menubar (f, first_time) update_frame_menubar (f); UNBLOCK_INPUT; - - unbind_to (specpdl_count, Qnil); } /* Called from Fx_create_frame to create the inital menubar of a frame @@ -1674,7 +1758,7 @@ initialize_frame_menubar (f) /* This function is called before the first chance to redisplay the frame. It has to be, so the frame will have the right size. */ FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f)); - set_frame_menubar (f, 1); + set_frame_menubar (f, 1, 1); } /* Get rid of the menu bar of frame F, and free its storage. @@ -1691,10 +1775,8 @@ free_frame_menubar (f) if (menubar_widget) { - id = frame_vector_add_frame (f); BLOCK_INPUT; - lw_destroy_all_widgets ((LWLIB_ID) id); - XVECTOR (frame_vector)->contents[id] = Qnil; + lw_destroy_all_widgets ((LWLIB_ID) f->display.x->id); UNBLOCK_INPUT; } } @@ -1723,10 +1805,10 @@ free_frame_menubar (f) library. For the main windows, and popup menus, we use this counter, - which we increment each time after use. + which we increment each time after use. This starts from 1<<16. - For menu bars, we use the index of the frame in frame_vector - as the id. */ + For menu bars, we use numbers starting at 0, counted in + next_menubar_widget_id. */ LWLIB_ID widget_id_tick; #ifdef __STDC__ @@ -2478,11 +2560,9 @@ syms_of_xmenu () #ifdef USE_X_TOOLKIT widget_id_tick = (1<<16); + next_menubar_widget_id = 1; #endif - staticpro (&frame_vector); - frame_vector = Fmake_vector (make_number (10), Qnil); - defsubr (&Sx_popup_menu); defsubr (&Sx_popup_dialog); } -- 2.39.2