Commit 88766961 authored by Richard M. Stallman's avatar Richard M. Stallman
Browse files

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.
parent c8b5ebed
......@@ -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);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment