#include "keyboard.h"
#include "blockinput.h"
#include "puresize.h"
+#include "buffer.h"
#ifdef MSDOS
#include "msdos.h"
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;
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;
\f
-/* 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
\f
/* Initialize the menu_items structure if we haven't already done so.
Also mark it as currently empty. */
}
}
+/* 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
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;
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;
/* 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,
update_frame_menubar (f);
UNBLOCK_INPUT;
-
- unbind_to (specpdl_count, Qnil);
}
/* Called from Fx_create_frame to create the inital menubar of a frame
/* 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.
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;
}
}
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__
#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);
}