#include <X11/CoreP.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
+#include <X11/Xaw/Paned.h>
#include "../lwlib/lwlib.h"
#else /* not USE_X_TOOLKIT */
#include "../oldXMenu/XMenu.h"
extern Lisp_Object Qmenu_bar;
extern Lisp_Object Qmouse_click, Qevent_kind;
+extern Lisp_Object Vdefine_key_rebound_commands;
+
#ifdef USE_X_TOOLKIT
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;
+\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;
+
+ XSETFRAME (frame, f);
+
+ 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;
+ }
+
+ if (empty >= 0)
+ {
+ XVECTOR (frame_vector)->contents[empty] = frame;
+ return empty;
+ }
+
+ 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;
+}
\f
/* Initialize the menu_items structure if we haven't already done so.
Also mark it as currently empty. */
check if the original command matches the cached command. */
&& !(SYMBOLP (def) && SYMBOLP (XSYMBOL (def)->function)
&& EQ (def1, XSYMBOL (def)->function))
- /* If something had no key binding before, don't recheck it--
- doing that takes too much time and makes menus too slow. */
- && !(!NILP (cachelist) && NILP (savedkey)))
+ /* If something had no key binding before, don't recheck it
+ because that is too slow--except if we have a list of rebound
+ commands in Vdefine_key_rebound_commands, do recheck any command
+ that appears in that list. */
+ && (NILP (cachelist) || !NILP (savedkey)
+ || (! EQ (Qt, Vdefine_key_rebound_commands)
+ && !NILP (Fmemq (def, Vdefine_key_rebound_commands)))))
{
changed = 1;
descrip = Qnil;
We don't try both, because that makes easymenu menus slow. */
savedkey = Fwhere_is_internal (def, Qnil, Qt, Qnil);
-
- if (VECTORP (savedkey)
- && EQ (XVECTOR (savedkey)->contents[0], Qmenu_bar))
- savedkey = Qnil;
- /* Reject two-key sequences that start with a mouse click.
- These are probably menu items. */
- if (VECTORP (savedkey)
- && XVECTOR (savedkey)->size > 1
- && SYMBOLP (XVECTOR (savedkey)->contents[0]))
- {
- Lisp_Object tem;
-
- tem = Fget (XVECTOR (savedkey)->contents[0], Qevent_kind);
- if (EQ (tem, Qmouse_click))
- savedkey = Qnil;
- }
if (!NILP (savedkey))
{
descrip = Fkey_description (savedkey);
menu_item_enabled_p_1 (arg)
Lisp_Object arg;
{
+ /* If we got a quit from within the menu computation,
+ quit all the way out of it. This takes care of C-] in the debugger. */
+ if (CONSP (arg) && EQ (XCONS (arg)->car, Qquit))
+ Fsignal (Qquit, Qnil);
+
return Qnil;
}
FRAME_PTR f;
Lisp_Object x, y, window;
int keymaps = 0;
- int menubarp = 0;
int for_click = 0;
struct gcpro gcpro1;
check_x ();
/* Decode the first argument: find the window and the coordinates. */
- if (EQ (position, Qt))
+ if (EQ (position, Qt)
+ || (CONSP (position) && EQ (XCONS (position)->car, Qmenu_bar)))
{
/* Use the mouse's current position. */
- FRAME_PTR new_f = 0;
+ FRAME_PTR new_f = selected_frame;
Lisp_Object bar_window;
int part;
unsigned long time;
if (mouse_position_hook)
- (*mouse_position_hook) (&new_f, &bar_window, &part, &x, &y, &time);
+ (*mouse_position_hook) (&new_f, 1, &bar_window,
+ &part, &x, &y, &time);
if (new_f != 0)
XSETFRAME (window, new_f);
else
tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */
x = Fcar (tem);
y = Fcdr (tem);
-
- /* Determine whether this menu is handling a menu bar click. */
- tem = Fcar (Fcdr (Fcar (Fcdr (position))));
- if (CONSP (tem) && EQ (Fcar (tem), Qmenu_bar))
- menubarp = 1;
}
}
/* Display them in a menu. */
BLOCK_INPUT;
- selection = xmenu_show (f, xpos, ypos, menubarp, for_click,
+ selection = xmenu_show (f, xpos, ypos, for_click,
keymaps, title, &error_name);
UNBLOCK_INPUT;
check_x ();
/* Decode the first argument: find the window or frame to use. */
- if (EQ (position, Qt))
+ if (EQ (position, Qt)
+ || (CONSP (position) && EQ (XCONS (position)->car, Qmenu_bar)))
{
#if 0 /* Using the frame the mouse is on may not be right. */
/* Use the mouse's current position. */
- FRAME_PTR new_f = 0;
+ FRAME_PTR new_f = selected_frame;
Lisp_Object bar_window;
int part;
unsigned long time;
Lisp_Object x, y;
- (*mouse_position_hook) (&new_f, &bar_window, &part, &x, &y, &time);
+ (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
if (new_f != 0)
XSETFRAME (window, new_f);
else
window = selected_window;
#endif
- /* Decode the first argument: find the window and the coordinates. */
- if (EQ (position, Qt))
- window = selected_window;
+ window = selected_window;
}
else if (CONSP (position))
{
/* Display them in a dialog box. */
BLOCK_INPUT;
- selection = xdialog_show (f, 0, 0, title, &error_name);
+ selection = xdialog_show (f, 0, title, &error_name);
UNBLOCK_INPUT;
discard_menu_items ();
/* Loop in Xt until the menu pulldown or dialog popup has been
popped down (deactivated).
- NOTE: All calls to popup_get_selection() should be protected
+ NOTE: All calls to popup_get_selection should be protected
with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
+
void
-popup_get_selection (initial_event)
+popup_get_selection (initial_event, dpyinfo, id)
XEvent *initial_event;
+ struct x_display_info *dpyinfo;
+ LWLIB_ID id;
{
XEvent event;
+ /* Define a queue to save up for later unreading
+ all X events that don't pertain to the menu. */
+ struct event_queue
+ {
+ XEvent event;
+ struct event_queue *next;
+ };
+
+ struct event_queue *queue = NULL;
+ struct event_queue *queue_tmp;
+
if (initial_event)
event = *initial_event;
else
while (1)
{
- XtDispatchEvent (&event);
- if (!popup_activated())
+ /* Handle expose events for editor frames right away. */
+ if (event.type == Expose)
+ process_expose_from_menu (event);
+ /* Make sure we don't consider buttons grabbed after menu goes. */
+ else if (event.type == ButtonRelease
+ && dpyinfo->display == event.xbutton.display)
+ dpyinfo->grabbed &= ~(1 << event.xbutton.button);
+ /* If the user presses a key, deactivate the menu.
+ The user is likely to do that if we get wedged. */
+ else if (event.type == KeyPress
+ && dpyinfo->display == event.xbutton.display)
+ {
+ popup_activated_flag = 0;
+ break;
+ }
+
+ /* Queue all events not for this popup,
+ except for Expose, which we've already handled.
+ Note that the X window is associated with the frame if this
+ is a menu bar popup, but not if it's a dialog box. So we use
+ x_non_menubar_window_to_frame, not x_any_window_to_frame. */
+ if (event.type != Expose
+ && (event.xany.display != dpyinfo->display
+ || x_non_menubar_window_to_frame (dpyinfo, event.xany.window)))
+ {
+ queue_tmp = (struct event_queue *) malloc (sizeof (struct event_queue));
+
+ if (queue_tmp != NULL)
+ {
+ queue_tmp->event = event;
+ queue_tmp->next = queue;
+ queue = queue_tmp;
+ }
+ }
+ else
+ XtDispatchEvent (&event);
+
+ if (!popup_activated ())
break;
XtAppNextEvent (Xt_app_con, &event);
}
+
+ /* Unread any events that we got but did not handle. */
+ while (queue != NULL)
+ {
+ queue_tmp = queue;
+ XPutBackEvent (queue_tmp->event.xany.display, &queue_tmp->event);
+ queue = queue_tmp->next;
+ free ((char *)queue_tmp);
+ /* Cause these events to get read as soon as we UNBLOCK_INPUT. */
+ interrupt_input_pending = 1;
+ }
}
/* Detect if a dialog or menu has been posted. */
+
int
popup_activated ()
{
LWLIB_ID id;
XtPointer client_data;
{
- Lisp_Object prefix;
- FRAME_PTR f = (FRAME_PTR) id;
+ Lisp_Object prefix, entry;
+ FRAME_PTR f = XFRAME (XVECTOR (frame_vector)->contents[id]);
Lisp_Object vector;
Lisp_Object *subprefix_stack;
int submenu_depth = 0;
i = 0;
while (i < f->menu_bar_items_used)
{
- Lisp_Object entry;
-
if (EQ (XVECTOR (vector)->contents[i], Qnil))
{
subprefix_stack[submenu_depth++] = prefix;
else
{
entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
- if ((int) client_data == i)
+ /* The EMACS_INT cast avoids a warning. There's no problem
+ as long as pointers have enough bits to hold small integers. */
+ if ((int) (EMACS_INT) client_data == i)
{
int j;
struct input_event buf;
XSETFRAME (frame, f);
buf.kind = menu_bar_event;
- buf.frame_or_window = Fcons (frame, Qmenu_bar);
+ buf.frame_or_window = Fcons (frame, Fcons (Qmenu_bar, Qnil));
kbd_buffer_store_event (&buf);
for (j = 0; j < submenu_depth; j++)
if (!NILP (descrip))
wv->key = (char *) XSTRING (descrip)->data;
wv->value = 0;
- wv->call_data = (!NILP (def) ? (void *) i : 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);
prev_wv = wv;
\f
extern void EmacsFrameSetCharSize ();
-/* Recompute the menu bar of frame F. */
+/* Recompute all the widgets of frame F, when the menu bar
+ has been changed. */
static void
update_frame_menubar (f)
UNBLOCK_INPUT;
}
+/* Set the contents of the menubar widgets of frame F.
+ The argument FIRST_TIME is currently ignored;
+ it is set the first time this is called, from initialize_frame_menubar. */
+
void
set_frame_menubar (f, first_time)
FRAME_PTR f;
int first_time;
{
Widget menubar_widget = f->display.x->menubar_widget;
- int id = (int) f;
- Lisp_Object tail, items;
+ Lisp_Object tail, items, frame;
widget_value *wv, *first_wv, *prev_wv = 0;
int i;
+ int id;
+ int count;
+ int specpdl_count = specpdl_ptr - specpdl;
- BLOCK_INPUT;
+ count = inhibit_garbage_collection ();
+
+ specbind (Qinhibit_quit, Qt);
+
+ id = frame_vector_add_frame (f);
wv = malloc_widget_value ();
wv->name = "menubar";
f->menu_bar_items_used = menu_items_used;
menu_items = Qnil;
+ unbind_to (count, Qnil);
+
+ BLOCK_INPUT;
+
if (menubar_widget)
{
/* Disable resizing (done for Motif!) */
/* 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 (id, first_wv, 1);
+ lw_modify_all_widgets ((LWLIB_ID) id, first_wv, 1);
/* Re-enable the edit widget to resize. */
lw_allow_resizing (f->display.x->widget, True);
else
{
menubar_widget = lw_create_widget ("menubar", "menubar",
- id, first_wv,
+ (LWLIB_ID) id, first_wv,
f->display.x->column_widget,
0,
popup_activate_callback,
popup_deactivate_callback);
f->display.x->menubar_widget = menubar_widget;
}
+
+ {
+ int menubar_size
+ = (f->display.x->menubar_widget
+ ? (f->display.x->menubar_widget->core.height
+ + f->display.x->menubar_widget->core.border_width)
+ : 0);
+
+ if (FRAME_EXTERNAL_MENU_BAR (f))
+ {
+ Dimension ibw = 0;
+ XtVaGetValues (f->display.x->column_widget,
+ XtNinternalBorderWidth, &ibw, NULL);
+ menubar_size += ibw;
+ }
+
+ f->display.x->menubar_height = menubar_size;
+ }
free_menubar_widget_value_tree (first_wv);
- /* Don't update the menubar the first time it is created via x_window. */
- if (!first_time)
- update_frame_menubar (f);
+ update_frame_menubar (f);
+
+ unbind_to (specpdl_count, Qnil);
UNBLOCK_INPUT;
}
int id;
menubar_widget = f->display.x->menubar_widget;
- id = (int) f;
if (menubar_widget)
{
+ id = frame_vector_add_frame (f);
BLOCK_INPUT;
- lw_destroy_all_widgets (id);
+ lw_destroy_all_widgets ((LWLIB_ID) id);
+ XVECTOR (frame_vector)->contents[id] = Qnil;
UNBLOCK_INPUT;
}
}
/* F is the frame the menu is for.
X and Y are the frame-relative specified position,
relative to the inside upper left corner of the frame F.
- MENUBARP is 1 if this menu came from the menu bar.
FOR_CLICK if this menu was invoked for a mouse click.
KEYMAPS is 1 if this menu was specified with keymaps;
in that case, we return a list containing the chosen item's value
#ifdef USE_X_TOOLKIT
/* We need a unique id for each widget handled by the Lucid Widget
- library. This includes the frame main windows, popup menu and
- dialog box. */
+ library.
+
+ For the main windows, and popup menus, we use this counter,
+ which we increment each time after use.
+
+ For menu bars, we use the index of the frame in frame_vector
+ as the id. */
LWLIB_ID widget_id_tick;
#ifdef __STDC__
}
static Lisp_Object
-xmenu_show (f, x, y, menubarp, for_click, keymaps, title, error)
+xmenu_show (f, x, y, for_click, keymaps, title, error)
FRAME_PTR f;
int x;
int y;
- int menubarp; /* This arg is unused in Xt version. */
int for_click;
int keymaps;
Lisp_Object title;
char **error;
{
int i;
- int menu_id;
+ LWLIB_ID menu_id;
Widget menu;
Arg av [2];
int ac = 0;
= (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
int submenu_depth = 0;
- /* Define a queue to save up for later unreading
- all X events that don't pertain to the menu. */
- struct event_queue
- {
- XEvent event;
- struct event_queue *next;
- };
-
- struct event_queue *queue = NULL;
- struct event_queue *queue_tmp;
-
Position root_x, root_y;
int first_pane;
}
/* Actually create the menu. */
- menu_id = ++widget_id_tick;
+ menu_id = widget_id_tick++;
menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
f->display.x->widget, 1, 0,
popup_selection_callback,
popup_activated_flag = 1;
/* Process events that apply to the menu. */
- popup_get_selection ((XEvent *) 0);
+ popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id);
- pop_down:
/* fp turned off the following statement and wrote a comment
that it is unnecessary--that the menu has already disappeared.
- I observer that is not so. -- rms. */
- /* Make sure the menu disappears. */
+ Nowadays the menu disappears ok, all right, but
+ we need to delete the widgets or multiple ones will pile up. */
lw_destroy_all_widgets (menu_id);
- /* Unread any events that we got but did not handle. */
- while (queue != NULL)
- {
- queue_tmp = queue;
- XPutBackEvent (FRAME_X_DISPLAY (f), &queue_tmp->event);
- queue = queue_tmp->next;
- free ((char *)queue_tmp);
- /* Cause these events to get read as soon as we UNBLOCK_INPUT. */
- interrupt_input_pending = 1;
- }
-
/* Find the selected item, and its pane, to return
the proper value. */
if (menu_item_selection != 0)
{
- Lisp_Object prefix;
+ Lisp_Object prefix, entry;
prefix = Qnil;
i = 0;
while (i < menu_items_used)
{
- Lisp_Object entry;
-
if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
{
subprefix_stack[submenu_depth++] = prefix;
LWLIB_ID id;
XtPointer client_data;
{
- if ((int)client_data != -1)
+ /* The EMACS_INT cast avoids a warning. There's no problem
+ as long as pointers have enough bits to hold small integers. */
+ if ((int) (EMACS_INT) client_data != -1)
menu_item_selection = (Lisp_Object *) client_data;
BLOCK_INPUT;
lw_destroy_all_widgets (id);
UNBLOCK_INPUT;
+ popup_activated_flag = 0;
}
static char * button_names [] = {
"button6", "button7", "button8", "button9", "button10" };
static Lisp_Object
-xdialog_show (f, menubarp, keymaps, title, error)
+xdialog_show (f, keymaps, title, error)
FRAME_PTR f;
- int menubarp;
int keymaps;
Lisp_Object title;
char **error;
{
int i, nb_buttons=0;
- int dialog_id;
+ LWLIB_ID dialog_id;
Widget menu;
char dialog_name[6];
widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
- /* Define a queue to save up for later unreading
- all X events that don't pertain to the menu. */
- struct event_queue
- {
- XEvent event;
- struct event_queue *next;
- };
-
- struct event_queue *queue = NULL;
- struct event_queue *queue_tmp;
-
/* Number of elements seen so far, before boundary. */
int left_count = 0;
/* 1 means we've seen the boundary between left-hand elts and right-hand. */
}
/* Actually create the dialog. */
- dialog_id = ++widget_id_tick;
+ dialog_id = widget_id_tick++;
menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
f->display.x->widget, 1, 0,
dialog_selection_callback, 0);
/* Display the menu. */
lw_pop_up_all_widgets (dialog_id);
+ popup_activated_flag = 1;
/* Process events that apply to the menu. */
- while (1)
- {
- XEvent event;
-
- XtAppNextEvent (Xt_app_con, &event);
- if (event.type == ButtonRelease)
- {
- XtDispatchEvent (&event);
- break;
- }
- else if (event.type == Expose)
- process_expose_from_menu (event);
- XtDispatchEvent (&event);
- if (XtWindowToWidget (FRAME_X_DISPLAY (f), event.xany.window) != menu)
- {
- queue_tmp = (struct event_queue *) malloc (sizeof (struct event_queue));
+ popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id);
- if (queue_tmp != NULL)
- {
- queue_tmp->event = event;
- queue_tmp->next = queue;
- queue = queue_tmp;
- }
- }
- }
- pop_down:
-
-#ifdef HAVE_X_WINDOWS
- /* State that no mouse buttons are now held.
- That is not necessarily true, but the fiction leads to reasonable
- results, and it is a pain to ask which are actually held now
- or track this in the loop above. */
- FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
-#endif
-
- /* Unread any events that we got but did not handle. */
- while (queue != NULL)
- {
- queue_tmp = queue;
- XPutBackEvent (FRAME_X_DISPLAY (f), &queue_tmp->event);
- queue = queue_tmp->next;
- free ((char *)queue_tmp);
- /* Cause these events to get read as soon as we UNBLOCK_INPUT. */
- interrupt_input_pending = 1;
- }
+ lw_destroy_all_widgets (dialog_id);
/* Find the selected item, and its pane, to return
the proper value. */
#else /* not USE_X_TOOLKIT */
static Lisp_Object
-xmenu_show (f, x, y, menubarp, for_click, keymaps, title, error)
+xmenu_show (f, x, y, for_click, keymaps, title, error)
FRAME_PTR f;
int x, y;
- int menubarp;
int for_click;
int keymaps;
Lisp_Object title;
x, y, ButtonReleaseMask, &datap);
+#ifdef HAVE_X_WINDOWS
/* Assume the mouse has moved out of the X window.
If it has actually moved in, we will get an EnterNotify. */
- x_mouse_leave ();
+ x_mouse_leave (FRAME_X_DISPLAY_INFO (f));
+#endif
switch (status)
{
widget_id_tick = (1<<16);
#endif
+ staticpro (&frame_vector);
+ frame_vector = Fmake_vector (make_number (10), Qnil);
+
defsubr (&Sx_popup_menu);
defsubr (&Sx_popup_dialog);
}