/* Rewritten for clarity and GC protection by rms in Feb 94. */
-#include <stdio.h>
-
/* On 4.3 this loses if it comes after xterm.h. */
#include <signal.h>
#include <config.h>
+
+#include <stdio.h>
#include "lisp.h"
#include "termhooks.h"
#include "frame.h"
#include "window.h"
#include "keyboard.h"
#include "blockinput.h"
+#include "puresize.h"
/* This may include sys/types.h, and that somehow loses
if this is not done before the other system files. */
#include <X11/IntrinsicP.h>
#include <X11/CoreP.h>
#include <X11/StringDefs.h>
+#include <X11/Shell.h>
#include <X11/Xaw/Paned.h>
#include "../lwlib/lwlib.h"
#include "../lwlib/xlwmenuP.h"
Lisp_Object savedkey, descrip;
Lisp_Object def1;
int changed = 0;
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
/* If a help string follows the item string, skip it. */
if (CONSP (XCONS (item1)->cdr)
descrip = XCONS (cachelist)->cdr;
}
+ GCPRO4 (def, def1, savedkey, descrip);
+
/* Is it still valid? */
def1 = Qnil;
if (!NILP (savedkey))
def1 = Fkey_binding (savedkey, Qnil);
/* If not, update it. */
if (! EQ (def1, def)
+ /* If the command is an alias for another
+ (such as easymenu.el and lmenu.el set it up),
+ 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)))
changed = 1;
descrip = Qnil;
savedkey = Fwhere_is_internal (def, Qnil, Qt, Qnil);
+ /* If the command is an alias for another
+ (such as easymenu.el and lmenu.el set it up),
+ see if the original command name has equivalent keys. */
+ if (SYMBOLP (def) && SYMBOLP (XSYMBOL (def)->function))
+ savedkey = Fwhere_is_internal (XSYMBOL (def)->function,
+ Qnil, Qt, Qnil);
+
if (VECTORP (savedkey)
&& EQ (XVECTOR (savedkey)->contents[0], Qmenu_bar))
savedkey = Qnil;
/* Cache the data we just got in a sublist of the menu binding. */
if (NILP (cachelist))
- XCONS (item1)->cdr = Fcons (Fcons (savedkey, descrip), def);
+ {
+ CHECK_IMPURE (item1);
+ XCONS (item1)->cdr = Fcons (Fcons (savedkey, descrip), def);
+ }
else if (changed)
{
XCONS (cachelist)->car = savedkey;
XCONS (cachelist)->cdr = descrip;
}
+ UNGCPRO;
*descrip_ptr = descrip;
return def;
}
static Lisp_Object
menu_item_enabled_p (def, notreal)
Lisp_Object def;
+ int notreal;
{
Lisp_Object enabled, tem;
Lisp_Object descrip;
Lisp_Object tem, enabled;
- def = menu_item_equiv_key (item_string, item1, &descrip);
-
- /* GCPRO because we will call eval.
+ /* GCPRO because ...enabled_p will call eval
+ and ..._equiv_key may autoload something.
Protecting KEYMAP preserves everything we use;
aside from that, must protect whatever might be
a string. Since there's no GCPRO5, we refetch
item_string instead of protecting it. */
+ descrip = def = Qnil;
GCPRO4 (keymap, pending_maps, def, descrip);
+
+ def = menu_item_equiv_key (item_string, item1, &descrip);
enabled = menu_item_enabled_p (def, notreal);
UNGCPRO;
else
{
Lisp_Object submap;
+ GCPRO4 (keymap, pending_maps, descrip, item_string);
submap = get_keymap_1 (def, 0, 1);
+ UNGCPRO;
#ifndef USE_X_TOOLKIT
/* Indicate visually that this is a submenu. */
if (!NILP (submap))
Lisp_Object descrip;
Lisp_Object tem, enabled;
- def = menu_item_equiv_key (item_string, item1, &descrip);
-
- /* GCPRO because we will call eval.
+ /* GCPRO because ...enabled_p will call eval
+ and ..._equiv_key may autoload something.
Protecting KEYMAP preserves everything we use;
aside from that, must protect whatever might be
a string. Since there's no GCPRO5, we refetch
item_string instead of protecting it. */
GCPRO4 (keymap, pending_maps, def, descrip);
+ descrip = def = Qnil;
+
+ def = menu_item_equiv_key (item_string, item1, &descrip);
enabled = menu_item_enabled_p (def, notreal);
+
UNGCPRO;
item_string = XCONS (item1)->car;
else
{
Lisp_Object submap;
+ GCPRO4 (keymap, pending_maps, descrip, item_string);
submap = get_keymap_1 (def, 0, 1);
+ UNGCPRO;
#ifndef USE_X_TOOLKIT
if (!NILP (submap))
item_string = concat2 (item_string,
return Qnil;
}
+#ifdef __STDC__
+static Lisp_Object *volatile menu_item_selection;
+#else
static Lisp_Object *menu_item_selection;
+#endif
static void
popup_selection_callback (widget, id, client_data)
int x, y;
{
return (y >= 0
+ && f->display.x->menubar_widget != 0
&& y < f->display.x->menubar_widget->core.height
&& x >= 0
&& x < last_menu_bar_item_end
#ifdef USE_X_TOOLKIT
+extern unsigned last_event_timestamp;
+extern Lisp_Object Vdouble_click_time;
+
extern unsigned int x_mouse_grabbed;
extern Lisp_Object Vmouse_depressed;
int menu_id;
Widget menu;
XlwMenuWidget menubar = (XlwMenuWidget) f->display.x->menubar_widget;
+ Arg av [2];
+ int ac = 0;
/* This is the menu bar item (if any) that led to this menu. */
widget_value *menubar_item = 0;
Position root_x, root_y;
+ int first_pane;
+ int next_release_must_exit = 0;
+
*error = NULL;
if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
menubarp = 0;
/* Offset the coordinates to root-relative. */
+ if (f->display.x->menubar_widget != 0)
+ y += f->display.x->menubar_widget->core.height;
XtTranslateCoords (f->display.x->widget,
- x, y + f->display.x->menubar_widget->core.height,
- &root_x, &root_y);
+ x, y, &root_x, &root_y);
x = root_x;
y = root_y;
wv->value = 0;
wv->enabled = 1;
first_wv = wv;
+ first_pane = 1;
/* Loop over all panes and items, filling in the tree. */
i = 0;
submenu_stack[submenu_depth++] = save_wv;
save_wv = prev_wv;
prev_wv = 0;
+ first_pane = 1;
i++;
}
else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
{
prev_wv = save_wv;
save_wv = submenu_stack[--submenu_depth];
+ first_pane = 0;
i++;
}
else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
/* If the pane has a meaningful name,
make the pane a top-level menu item
with its items as a submenu beneath it. */
- if (strcmp (pane_string, ""))
+ if (!keymaps && strcmp (pane_string, ""))
{
wv = malloc_widget_value ();
if (save_wv)
wv->name++;
wv->value = 0;
wv->enabled = 1;
+ save_wv = wv;
+ prev_wv = 0;
}
- save_wv = wv;
- prev_wv = 0;
+ else if (first_pane)
+ {
+ save_wv = wv;
+ prev_wv = 0;
+ }
+ first_pane = 0;
i += MENU_ITEMS_PANE_LENGTH;
}
else
menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
f->display.x->widget, 1, 0,
popup_selection_callback, popup_down_callback);
+
+ /* Don't allow any geometry request from the user. */
+ XtSetArg (av[ac], XtNgeometry, 0); ac++;
+ XtSetValues (menu, av, ac);
+
/* Free the widget_value objects we used to specify the contents. */
free_menubar_widget_value_tree (first_wv);
/* No need to check a second time since this is done in the XEvent loop.
This slows done the execution. */
-#if 0
+#ifdef XMENU_FOO
/* Check again whether the mouse has moved to another menu bar item. */
if (check_mouse_other_menu_bar (f))
{
/* The mouse moved into a different menu bar item.
We should bring up that item's menu instead.
First pop down this menu. */
+#if 0 /* xlwmenu.c now does this. */
XtUngrabPointer ((Widget)
((XlwMenuWidget)
((CompositeWidget)menu)->composite.children[0]),
CurrentTime);
+#endif
lw_destroy_all_widgets (menu_id);
goto pop_down;
}
while (1)
{
XEvent event;
+ int queue_and_exit = 0;
+ int in_this_menu = 0, in_menu_bar = 0;
+ Widget widget;
XtAppNextEvent (Xt_app_con, &event);
- if (event.type == ButtonRelease)
+
+ /* Check whether the event happened in the menu
+ or any child of it. */
+ widget = XtWindowToWidget (XDISPLAY event.xany.window);
+
+ while (widget)
{
- XtDispatchEvent (&event);
- if (! menubarp)
+ if (widget == menu)
{
- /* Do the work of construct_mouse_click since it can't
- be called. Initially, the popup menu has been called
- from a ButtonPress in the edit_widget. Then the mouse
- has been set to grabbed. Reset it now. */
- x_mouse_grabbed &= ~(1 << event.xbutton.button);
- if (!x_mouse_grabbed)
- Vmouse_depressed = Qnil;
+ in_this_menu = 1;
+ break;
}
- break;
+ if (widget == f->display.x->menubar_widget)
+ {
+ in_menu_bar = 1;
+ break;
+ }
+ widget = XtParent (widget);
+ }
+
+ if (event.type == ButtonRelease)
+ {
+ /* Do the work of construct_mouse_click since it can't
+ be called. Initially, the popup menu has been called
+ from a ButtonPress in the edit_widget. Then the mouse
+ has been set to grabbed. Reset it now. */
+ x_mouse_grabbed &= ~(1 << event.xbutton.button);
+ if (!x_mouse_grabbed)
+ Vmouse_depressed = Qnil;
+
+ /* If we release the button soon without selecting anything,
+ stay in the loop--that is, leave the menu posted.
+ Otherwise, exit this loop and thus pop down the menu. */
+ if (! in_this_menu
+ && (next_release_must_exit
+ || !(((XButtonEvent *) (&event))->time - last_event_timestamp
+ < XINT (Vdouble_click_time))))
+ break;
+ }
+ /* A button press outside the menu => pop it down. */
+ else if (event.type == ButtonPress && !in_this_menu)
+ break;
+ else if (event.type == ButtonPress)
+ next_release_must_exit = 1;
+ else if (event.type == KeyPress)
+ {
+ /* Exit the loop, but first queue this event for reuse. */
+ queue_and_exit = 1;
}
else if (event.type == Expose)
process_expose_from_menu (event);
- else if (event.type == MotionNotify)
+ /* If the mouse moves to a different menu bar item, switch to
+ that item's menu. But only if the button is still held down. */
+ else if (event.type == MotionNotify
+ && x_mouse_grabbed)
{
int event_x = (event.xmotion.x_root
- (f->display.x->widget->core.x
/* The mouse moved into a different menu bar item.
We should bring up that item's menu instead.
First pop down this menu. */
+#if 0 /* xlwmenu.c now does this. */
XtUngrabPointer ((Widget)
((XlwMenuWidget)
((CompositeWidget)menu)->composite.children[0]),
event.xbutton.time);
+#endif
lw_destroy_all_widgets (menu_id);
/* Put back an event that will bring up the other item's menu. */
break;
}
}
+ else if (event.type == UnmapNotify)
+ {
+ /* If the menu disappears, there is no need to stay in the
+ loop. */
+ if (event.xunmap.window == menu->core.window)
+ break;
+ }
XtDispatchEvent (&event);
- if (XtWindowToWidget(XDISPLAY event.xany.window) != menu)
+
+ if (queue_and_exit || (!in_this_menu && !in_menu_bar))
{
queue_tmp
= (struct event_queue *) malloc (sizeof (struct event_queue));
queue = queue_tmp;
}
}
+ if (queue_and_exit)
+ break;
}
pop_down:
#if 0 /* This causes crashes, and seems to be redundant -- rms. */
lw_modify_all_widgets (dialog_id, first_wv, True);
#endif
- lw_modify_all_widgets (dialog_id, first_wv->contents->next, True);
+ lw_modify_all_widgets (dialog_id, first_wv->contents, True);
/* Free the widget_value objects we used to specify the contents. */
free_menubar_widget_value_tree (first_wv);
break;
case XM_FAILURE:
- XMenuDestroy (XDISPLAY menu);
*error = "Can't activate menu";
case XM_IA_SELECT:
case XM_NO_SELECT: