/* 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"
+#include "buffer.h"
+#ifdef MSDOS
+#include "msdos.h"
+#endif
+
+#ifdef HAVE_X_WINDOWS
/* This may include sys/types.h, and that somehow loses
if this is not done before the other system files. */
#include "xterm.h"
+#endif
/* Load sys/types.h if not already loaded.
In some systems loading it twice is suicidal. */
#include "dispextern.h"
-#ifdef HAVE_X11
-#include "../oldXMenu/XMenu.h"
-#else
-#include <X/XMenu.h>
-#endif
-
+#ifdef HAVE_X_WINDOWS
#ifdef USE_X_TOOLKIT
#include <X11/Xlib.h>
#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"
-#endif /* USE_X_TOOLKIT */
+#else /* not USE_X_TOOLKIT */
+#include "../oldXMenu/XMenu.h"
+#endif /* not USE_X_TOOLKIT */
+#endif /* HAVE_X_WINDOWS */
#define min(x,y) (((x) < (y)) ? (x) : (y))
#define max(x,y) (((x) > (y)) ? (x) : (y))
#define FALSE 0
#endif /* no TRUE */
-#ifdef HAVE_X11
-extern Display *x_current_display;
-#else
-#define ButtonReleaseMask ButtonReleased
-#endif /* not HAVE_X11 */
-
-/* We need a unique id for each popup menu and dialog box. */
-static unsigned int popup_id_tick;
+Lisp_Object Qdebug_on_next_call;
extern Lisp_Object Qmenu_enable;
extern Lisp_Object Qmenu_bar;
+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;
-static int string_width ();
static Lisp_Object xdialog_show ();
+void popup_get_selection ();
#endif
static Lisp_Object xmenu_show ();
Each pane is described by 3 elements in the vector:
t, the pane name, the pane's prefix key.
- Then follow the pane's items, with 4 elements per item:
+ Then follow the pane's items, with 5 elements per item:
the item string, the enable flag, the item's value,
- and the equivalent keyboard key's description string.
+ the definition, and the equivalent keyboard key's description string.
In some cases, multiple levels of menus may be described.
A single vector slot containing nil indicates the start of a submenu.
#define MENU_ITEMS_ITEM_ENABLE 1
#define MENU_ITEMS_ITEM_VALUE 2
#define MENU_ITEMS_ITEM_EQUIV_KEY 3
-#define MENU_ITEMS_ITEM_LENGTH 4
+#define MENU_ITEMS_ITEM_DEFINITION 4
+#define MENU_ITEMS_ITEM_LENGTH 5
static Lisp_Object menu_items;
/* Current depth within submenus. */
static int menu_items_submenu_depth;
+/* Flag which when set indicates a dialog or menu has been posted by
+ Xt on behalf of one of the widget sets. */
+static int popup_activated_flag;
+
+static int next_menubar_widget_id;
+\f
+#ifdef USE_X_TOOLKIT
+
+/* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
+
+static struct frame *
+menubar_id_to_frame (id)
+ LWLIB_ID id;
+{
+ Lisp_Object tail, frame;
+ FRAME_PTR f;
+
+ for (tail = Vframe_list; GC_CONSP (tail); tail = XCONS (tail)->cdr)
+ {
+ frame = XCONS (tail)->car;
+ if (!GC_FRAMEP (frame))
+ continue;
+ f = XFRAME (frame);
+ if (f->output_data.nothing == 1)
+ continue;
+ if (f->output_data.x->id == id)
+ return f;
+ }
+ return 0;
+}
+
+#endif
+\f
/* Initialize the menu_items structure if we haven't already done so.
Also mark it as currently empty. */
/* Push one menu item into the current pane.
NAME is the string to display. ENABLE if non-nil means
this item can be selected. KEY is the key generated by
- choosing this item. EQUIV is the textual description
- of the keyboard equivalent for this item (or nil if none). */
+ choosing this item, or nil if this item doesn't really have a definition.
+ DEF is the definition of this item.
+ EQUIV is the textual description of the keyboard equivalent for
+ this item (or nil if none). */
static void
-push_menu_item (name, enable, key, equiv)
- Lisp_Object name, enable, key, equiv;
+push_menu_item (name, enable, key, def, equiv)
+ Lisp_Object name, enable, key, def, equiv;
{
if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
grow_menu_items ();
XVECTOR (menu_items)->contents[menu_items_used++] = enable;
XVECTOR (menu_items)->contents[menu_items_used++] = key;
XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
+ XVECTOR (menu_items)->contents[menu_items_used++] = def;
}
\f
/* Figure out the current keyboard equivalent of a menu item ITEM1.
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 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 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
+ 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;
- savedkey = Fwhere_is_internal (def, Qnil, Qt, Qnil);
- if (VECTORP (savedkey)
- && EQ (XVECTOR (savedkey)->contents[0], Qmenu_bar))
- savedkey = 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);
+ else
+ /* Otherwise look up the specified command itself.
+ We don't try both, because that makes easymenu menus slow. */
+ savedkey = Fwhere_is_internal (def, Qnil, Qt, Qnil);
+
if (!NILP (savedkey))
{
descrip = Fkey_description (savedkey);
/* 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;
}
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;
}
static Lisp_Object
menu_item_enabled_p (def, notreal)
Lisp_Object def;
+ int notreal;
{
Lisp_Object enabled, tem;
enabled = Qt;
if (notreal)
return enabled;
- if (XTYPE (def) == Lisp_Symbol)
+ if (SYMBOLP (def))
{
/* No property, or nil, means enable.
Otherwise, enable if value is not nil. */
push_menu_pane (pane_name, prefix);
- for (tail = keymap; XTYPE (tail) == Lisp_Cons; tail = XCONS (tail)->cdr)
+ for (tail = keymap; CONSP (tail); tail = XCONS (tail)->cdr)
{
/* Look at each key binding, and if it has a menu string,
make a menu item from it. */
item = XCONS (tail)->car;
- if (XTYPE (item) == Lisp_Cons)
+ if (CONSP (item))
{
item1 = XCONS (item)->cdr;
- if (XTYPE (item1) == Lisp_Cons)
+ if (CONSP (item1))
{
item_string = XCONS (item1)->car;
- if (XTYPE (item_string) == Lisp_String)
+ if (STRINGP (item_string))
{
/* This is the real definition--the function to run. */
Lisp_Object def;
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))
item_string = concat2 (item_string,
build_string (" >"));
#endif
- push_menu_item (item_string, enabled, XCONS (item)->car,
+ /* If definition is nil, pass nil as the key. */
+ push_menu_item (item_string, enabled,
+ XCONS (item)->car, def,
descrip);
#ifdef USE_X_TOOLKIT
/* Display a submenu using the toolkit. */
}
}
}
- else if (XTYPE (item) == Lisp_Vector)
+ else if (VECTORP (item))
{
/* Loop over the char values represented in the vector. */
int len = XVECTOR (item)->size;
for (c = 0; c < len; c++)
{
Lisp_Object character;
- XFASTINT (character) = c;
+ XSETFASTINT (character, c);
item1 = XVECTOR (item)->contents[c];
- if (XTYPE (item1) == Lisp_Cons)
+ if (CONSP (item1))
{
item_string = XCONS (item1)->car;
- if (XTYPE (item_string) == Lisp_String)
+ if (STRINGP (item_string))
{
Lisp_Object def;
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,
build_string (" >"));
#endif
+ /* If definition is nil, pass nil as the key. */
push_menu_item (item_string, enabled, character,
- descrip);
+ def, descrip);
#ifdef USE_X_TOOLKIT
if (! NILP (submap))
{
{
item = Fcar (tail);
if (STRINGP (item))
- push_menu_item (item, Qnil, Qnil, Qnil);
+ push_menu_item (item, Qnil, Qnil, Qt, Qnil);
else if (NILP (item))
push_left_right_boundary ();
else
CHECK_CONS (item, 0);
item1 = Fcar (item);
CHECK_STRING (item1, 1);
- push_menu_item (item1, Qt, Fcdr (item), Qnil);
+ push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil);
}
}
}
"Pop up a deck-of-cards menu and return user's selection.\n\
POSITION is a position specification. This is either a mouse button event\n\
or a list ((XOFFSET YOFFSET) WINDOW)\n\
-where XOFFSET and YOFFSET are positions in characters from the top left\n\
+where XOFFSET and YOFFSET are positions in pixels from the top left\n\
corner of WINDOW's frame. (WINDOW may be a frame object instead of a window.)\n\
This controls the position of the center of the first line\n\
in the first pane of the menu, not the top left of the menu as a whole.\n\
FRAME_PTR f;
Lisp_Object x, y, window;
int keymaps = 0;
- int menubarp = 0;
+ int for_click = 0;
struct gcpro gcpro1;
if (! NILP (position))
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, 1, &bar_window,
+ &part, &x, &y, &time);
if (new_f != 0)
- XSET (window, Lisp_Frame, new_f);
+ XSETFRAME (window, new_f);
else
{
window = selected_window;
- XFASTINT (x) = 0;
- XFASTINT (y) = 0;
+ XSETFASTINT (x, 0);
+ XSETFASTINT (y, 0);
}
}
else
{
tem = Fcar (position);
- if (XTYPE (tem) == Lisp_Cons)
+ if (CONSP (tem))
{
window = Fcar (Fcdr (position));
x = Fcar (tem);
}
else
{
+ for_click = 1;
tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
window = Fcar (tem); /* POSN_WINDOW (tem) */
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 (XTYPE (Fcar (position)) != Lisp_Cons
- && CONSP (tem)
- && EQ (Fcar (tem), Qmenu_bar))
- menubarp = 1;
}
}
/* Decode where to put the menu. */
- if (XTYPE (window) == Lisp_Frame)
+ if (FRAMEP (window))
{
f = XFRAME (window);
-
xpos = 0;
ypos = 0;
}
- else if (XTYPE (window) == Lisp_Window)
+ else if (WINDOWP (window))
{
CHECK_LIVE_WINDOW (window, 0);
f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
- xpos = (FONT_WIDTH (f->display.x->font) * XWINDOW (window)->left);
- ypos = (f->display.x->line_height * XWINDOW (window)->top);
+ xpos = (FONT_WIDTH (f->output_data.x->font) * XWINDOW (window)->left);
+ ypos = (f->output_data.x->line_height * XWINDOW (window)->top);
}
else
/* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
keymap = Fkeymapp (menu);
tem = Qnil;
- if (XTYPE (menu) == Lisp_Cons)
+ if (CONSP (menu))
tem = Fkeymapp (Fcar (menu));
if (!NILP (keymap))
{
/* The first keymap that has a prompt string
supplies the menu title. */
- for (tem = menu, i = 0; XTYPE (tem) == Lisp_Cons; tem = Fcdr (tem))
+ for (tem = menu, i = 0; CONSP (tem); tem = Fcdr (tem))
{
Lisp_Object prompt;
/* Display them in a menu. */
BLOCK_INPUT;
- selection = xmenu_show (f, xpos, ypos, menubarp,
+ 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)
- XSET (window, Lisp_Frame, new_f);
+ 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))
{
Lisp_Object tem;
tem = Fcar (position);
- if (XTYPE (tem) == Lisp_Cons)
+ if (CONSP (tem))
window = Fcar (Fcdr (position));
else
{
/* Decode where to put the menu. */
- if (XTYPE (window) == Lisp_Frame)
+ if (FRAMEP (window))
f = XFRAME (window);
- else if (XTYPE (window) == Lisp_Window)
+ else if (WINDOWP (window))
{
CHECK_LIVE_WINDOW (window, 0);
f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
in the middle of frame F. */
{
Lisp_Object x, y, frame, newpos;
- XSET (frame, Lisp_Frame, f);
- XSET (x, Lisp_Int, x_pixel_width (f) / 2);
- XSET (y, Lisp_Int, x_pixel_height (f) / 2);
+ XSETFRAME (frame, f);
+ XSETINT (x, x_pixel_width (f) / 2);
+ XSETINT (y, x_pixel_height (f) / 2);
newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
return Fx_popup_menu (newpos,
/* 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 ();
\f
#ifdef USE_X_TOOLKIT
-static void
-dispatch_dummy_expose (w, x, y)
- Widget w;
- int x;
- int y;
-{
- XExposeEvent dummy;
-
- dummy.type = Expose;
- dummy.window = XtWindow (w);
- dummy.count = 0;
- dummy.serial = 0;
- dummy.send_event = 0;
- dummy.display = XtDisplay (w);
- dummy.x = x;
- dummy.y = y;
+/* Loop in Xt until the menu pulldown or dialog popup has been
+ popped down (deactivated).
- XtDispatchEvent ((XEvent *) &dummy);
-}
+ NOTE: All calls to popup_get_selection should be protected
+ with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
-static int
-string_width (mw, s)
- XlwMenuWidget mw;
- char* s;
+void
+popup_get_selection (initial_event, dpyinfo, id)
+ XEvent *initial_event;
+ struct x_display_info *dpyinfo;
+ LWLIB_ID id;
{
- XCharStruct xcs;
- int drop;
+ 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;
+ };
- XTextExtents (mw->menu.font, s, strlen (s), &drop, &drop, &drop, &xcs);
- return xcs.width;
-}
+ struct event_queue *queue = NULL;
+ struct event_queue *queue_tmp;
-static int
-event_is_in_menu_item (mw, event, name, string_w)
- XlwMenuWidget mw;
- struct input_event *event;
- char *name;
- int *string_w;
-{
- *string_w += (string_width (mw, name)
- + 2 * (mw->menu.horizontal_spacing
- + mw->menu.shadow_thickness));
- return XINT (event->x) < *string_w;
+ if (initial_event)
+ event = *initial_event;
+ else
+ XtAppNextEvent (Xt_app_con, &event);
+
+ while (1)
+ {
+ /* 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;
+ }
}
+/* 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.
-/* Return the menu bar key which corresponds to event EVENT in frame F. */
+ But first we recompute the menu bar contents (the whole tree).
-Lisp_Object
-map_event_to_object (event, f)
- struct input_event *event;
+ 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;
{
- int i,j, string_w;
- window_state* ws;
- XlwMenuWidget mw = (XlwMenuWidget) f->display.x->menubar_widget;
- widget_value *val;
+ if (f->output_data.x->saved_button_event->type != ButtonPress)
+ return;
+ set_frame_menubar (f, 0, 1);
- string_w = 0;
- /* Find the window */
- for (val = mw->menu.old_stack [0]->contents; val; val = val->next)
- {
- ws = &mw->menu.windows [0];
- if (ws && event_is_in_menu_item (mw, event, val->name, &string_w))
- {
- Lisp_Object items;
- int i;
+ BLOCK_INPUT;
+ XtDispatchEvent ((XEvent *) f->output_data.x->saved_button_event);
+ UNBLOCK_INPUT;
- items = FRAME_MENU_BAR_ITEMS (f);
+ /* Ignore this if we get it a second time. */
+ f->output_data.x->saved_button_event->type = 0;
+}
- for (i = 0; i < XVECTOR (items)->size; i += 3)
- {
- Lisp_Object pos, string, item;
- item = XVECTOR (items)->contents[i];
- string = XVECTOR (items)->contents[i + 1];
- pos = XVECTOR (items)->contents[i + 2];
- if (NILP (string))
- break;
+/* Detect if a dialog or menu has been posted. */
- if (!strcmp (val->name, XSTRING (string)->data))
- return item;
- }
- }
- }
- return Qnil;
+int
+popup_activated ()
+{
+ return popup_activated_flag;
}
-static Lisp_Object *menu_item_selection;
+
+/* This callback is invoked when the user selects a menubar cascade
+ pushbutton, but before the pulldown menu is posted. */
static void
-popup_selection_callback (widget, id, client_data)
+popup_activate_callback (widget, id, client_data)
Widget widget;
LWLIB_ID id;
XtPointer client_data;
{
- menu_item_selection = (Lisp_Object *) client_data;
+ popup_activated_flag = 1;
}
+/* This callback is called from the menu bar pulldown menu
+ when the user makes a selection.
+ Figure out what the user chose
+ and put the appropriate events into the keyboard buffer. */
+
static void
-popup_down_callback (widget, id, client_data)
+menubar_selection_callback (widget, id, client_data)
Widget widget;
LWLIB_ID id;
XtPointer client_data;
{
- BLOCK_INPUT;
- lw_destroy_all_widgets (id);
- UNBLOCK_INPUT;
+ Lisp_Object prefix, entry;
+ FRAME_PTR f = menubar_id_to_frame (id);
+ Lisp_Object vector;
+ Lisp_Object *subprefix_stack;
+ int submenu_depth = 0;
+ int i;
+
+ if (!f)
+ return;
+ subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object));
+ vector = f->menu_bar_vector;
+ prefix = Qnil;
+ i = 0;
+ while (i < f->menu_bar_items_used)
+ {
+ if (EQ (XVECTOR (vector)->contents[i], Qnil))
+ {
+ subprefix_stack[submenu_depth++] = prefix;
+ prefix = entry;
+ i++;
+ }
+ else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
+ {
+ prefix = subprefix_stack[--submenu_depth];
+ i++;
+ }
+ else if (EQ (XVECTOR (vector)->contents[i], Qt))
+ {
+ prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
+ i += MENU_ITEMS_PANE_LENGTH;
+ }
+ else
+ {
+ entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
+ /* 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;
+ Lisp_Object frame;
+
+ XSETFRAME (frame, f);
+ buf.kind = menu_bar_event;
+ buf.frame_or_window = Fcons (frame, Fcons (Qmenu_bar, Qnil));
+ kbd_buffer_store_event (&buf);
+
+ for (j = 0; j < submenu_depth; j++)
+ if (!NILP (subprefix_stack[j]))
+ {
+ buf.kind = menu_bar_event;
+ buf.frame_or_window = Fcons (frame, subprefix_stack[j]);
+ kbd_buffer_store_event (&buf);
+ }
+
+ if (!NILP (prefix))
+ {
+ buf.kind = menu_bar_event;
+ buf.frame_or_window = Fcons (frame, prefix);
+ kbd_buffer_store_event (&buf);
+ }
+
+ buf.kind = menu_bar_event;
+ buf.frame_or_window = Fcons (frame, entry);
+ kbd_buffer_store_event (&buf);
+
+ return;
+ }
+ i += MENU_ITEMS_ITEM_LENGTH;
+ }
+ }
}
+/* This callback is invoked when a dialog or menu is finished being
+ used and has been unposted. */
+
static void
-dialog_selection_callback (widget, id, client_data)
+popup_deactivate_callback (widget, id, client_data)
Widget widget;
LWLIB_ID id;
XtPointer client_data;
{
- if ((int)client_data != -1)
- menu_item_selection = (Lisp_Object *) client_data;
- BLOCK_INPUT;
- lw_destroy_all_widgets (id);
- UNBLOCK_INPUT;
+ popup_activated_flag = 0;
}
-/* This recursively calls free_widget_value() on the tree of widgets.
+
+/* This recursively calls free_widget_value on the tree of widgets.
It must free all data that was malloc'ed for these widget_values.
In Emacs, many slots are pointers into the data of Lisp_Strings, and
must be left alone. */
free_widget_value (wv);
UNBLOCK_INPUT;
}
+\f
+/* Return a tree of widget_value structures for a menu bar item
+ whose event type is ITEM_KEY (with string ITEM_NAME)
+ and whose contents come from the list of keymaps MAPS. */
-extern void EmacsFrameSetCharSize ();
-
-static void
-update_frame_menubar (f)
- FRAME_PTR f;
+static widget_value *
+single_submenu (item_key, item_name, maps)
+ Lisp_Object item_key, item_name, maps;
{
- struct x_display *x = f->display.x;
- int columns, rows;
- int menubar_changed;
-
- menubar_changed = (x->menubar_widget
- && !XtIsManaged (x->menubar_widget));
-
- if (! (menubar_changed))
- return;
-
- BLOCK_INPUT;
- /* Save the size of the frame because the pane widget doesn't accept to
- resize itself. So force it. */
- columns = f->width;
- rows = f->height;
-
+ widget_value *wv, *prev_wv, *save_wv, *first_wv;
+ int i;
+ int submenu_depth = 0;
+ Lisp_Object length;
+ int len;
+ Lisp_Object *mapvec;
+ widget_value **submenu_stack;
+ int mapno;
+ int previous_items = menu_items_used;
+ int top_level_items = 0;
- XawPanedSetRefigureMode (x->column_widget, 0);
-
- /* the order in which children are managed is the top to
- bottom order in which they are displayed in the paned window.
- First, remove the text-area widget.
- */
- XtUnmanageChild (x->edit_widget);
+ length = Flength (maps);
+ len = XINT (length);
- /* remove the menubar that is there now, and put up the menubar that
- should be there.
- */
- if (menubar_changed)
+ /* Convert the list MAPS into a vector MAPVEC. */
+ mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
+ for (i = 0; i < len; i++)
{
- XtManageChild (x->menubar_widget);
- XtMapWidget (x->menubar_widget);
- XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, 0);
+ mapvec[i] = Fcar (maps);
+ maps = Fcdr (maps);
}
+ menu_items_n_panes = 0;
- /* Re-manage the text-area widget */
- XtManageChild (x->edit_widget);
-
- /* and now thrash the sizes */
- XawPanedSetRefigureMode (x->column_widget, 1);
-
- /* Force the pane widget to resize itself with the right values. */
- EmacsFrameSetCharSize (x->edit_widget, columns, rows);
-
- UNBLOCK_INPUT;
-}
-
-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;
- widget_value *wv, *save_wv, *first_wv, *prev_wv = 0;
- int i;
+ /* Loop over the given keymaps, making a pane for each map.
+ But don't make a pane that is empty--ignore that map instead. */
+ for (i = 0; i < len; i++)
+ {
+ if (SYMBOLP (mapvec[i]))
+ {
+ top_level_items = 1;
+ push_menu_pane (Qnil, Qnil);
+ push_menu_item (item_name, Qt, item_key, mapvec[i], Qnil);
+ }
+ else
+ single_keymap_panes (mapvec[i], item_name, item_key, 0);
+ }
- BLOCK_INPUT;
+ /* Create a tree of widget_value objects
+ representing the panes and their items. */
+ submenu_stack
+ = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
wv = malloc_widget_value ();
- wv->name = "menubar";
+ wv->name = "menu";
wv->value = 0;
wv->enabled = 1;
- save_wv = first_wv = wv;
-
- if (NILP (items = FRAME_MENU_BAR_ITEMS (f)))
- items = FRAME_MENU_BAR_ITEMS (f) = menu_bar_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 ();
- if (prev_wv)
- prev_wv->next = wv;
- else
- save_wv->contents = wv;
- wv->name = (char *) XSTRING (string)->data;
- wv->value = 0;
- wv->enabled = 1;
- prev_wv = wv;
- }
-
- if (menubar_widget)
- lw_modify_all_widgets (id, first_wv, False);
- else
+ first_wv = wv;
+ save_wv = 0;
+ prev_wv = 0;
+
+ /* Loop over all panes and items made during this call
+ and construct a tree of widget_value objects.
+ Ignore the panes and items made by previous calls to
+ single_submenu, even though those are also in menu_items. */
+ i = previous_items;
+ while (i < menu_items_used)
{
- menubar_widget = lw_create_widget ("menubar", "menubar",
- id, first_wv,
- f->display.x->column_widget,
- 0, 0,
- 0, 0);
- f->display.x->menubar_widget = menubar_widget;
- XtVaSetValues (menubar_widget,
- XtNshowGrip, 0,
- XtNresizeToPreferred, 1,
- XtNallowResize, 1,
- 0);
- }
-
- 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);
-
- UNBLOCK_INPUT;
+ if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
+ {
+ submenu_stack[submenu_depth++] = save_wv;
+ save_wv = prev_wv;
+ prev_wv = 0;
+ i++;
+ }
+ else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
+ {
+ prev_wv = save_wv;
+ save_wv = submenu_stack[--submenu_depth];
+ i++;
+ }
+ else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
+ && submenu_depth != 0)
+ i += MENU_ITEMS_PANE_LENGTH;
+ /* Ignore a nil in the item list.
+ It's meaningful only for dialog boxes. */
+ else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
+ i += 1;
+ else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
+ {
+ /* Create a new pane. */
+ Lisp_Object pane_name, prefix;
+ char *pane_string;
+ pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
+ prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
+ pane_string = (NILP (pane_name)
+ ? "" : (char *) XSTRING (pane_name)->data);
+ /* If there is just one top-level pane, put all its items directly
+ under the top-level menu. */
+ if (menu_items_n_panes == 1)
+ pane_string = "";
+
+ /* 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, ""))
+ {
+ wv = malloc_widget_value ();
+ if (save_wv)
+ save_wv->next = wv;
+ else
+ first_wv->contents = wv;
+ wv->name = pane_string;
+ /* Ignore the @ that means "separate pane".
+ This is a kludge, but this isn't worth more time. */
+ if (!NILP (prefix) && wv->name[0] == '@')
+ wv->name++;
+ wv->value = 0;
+ wv->enabled = 1;
+ }
+ save_wv = wv;
+ prev_wv = 0;
+ i += MENU_ITEMS_PANE_LENGTH;
+ }
+ else
+ {
+ /* Create a new item within current pane. */
+ Lisp_Object item_name, enable, descrip, def;
+ item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
+ enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
+ descrip
+ = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
+ def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION];
+
+ wv = malloc_widget_value ();
+ if (prev_wv)
+ prev_wv->next = wv;
+ else
+ save_wv->contents = wv;
+
+ wv->name = (char *) XSTRING (item_name)->data;
+ if (!NILP (descrip))
+ wv->key = (char *) XSTRING (descrip)->data;
+ wv->value = 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;
+
+ i += MENU_ITEMS_ITEM_LENGTH;
+ }
+ }
+
+ /* If we have just one "menu item"
+ that was originally a button, return it by itself. */
+ if (top_level_items && first_wv->contents && first_wv->contents->next == 0)
+ {
+ wv = first_wv->contents;
+ free_widget_value (first_wv);
+ return wv;
+ }
+
+ return first_wv;
}
+\f
+extern void EmacsFrameSetCharSize ();
-void
-free_frame_menubar (f)
+/* Recompute all the widgets of frame F, when the menu bar
+ has been changed. */
+
+static void
+update_frame_menubar (f)
FRAME_PTR f;
{
- Widget menubar_widget;
- int id;
-
- menubar_widget = f->display.x->menubar_widget;
- id = (int) f;
+ struct x_output *x = f->output_data.x;
+ int columns, rows;
+ int menubar_changed;
- if (menubar_widget)
+ Dimension shell_height;
+
+ /* We assume the menubar contents has changed if the global flag is set,
+ or if the current buffer has changed, or if the menubar has never
+ been updated before.
+ */
+ menubar_changed = (x->menubar_widget
+ && !XtIsManaged (x->menubar_widget));
+
+ if (! (menubar_changed))
+ return;
+
+ BLOCK_INPUT;
+ /* Save the size of the frame because the pane widget doesn't accept to
+ resize itself. So force it. */
+ columns = f->width;
+ rows = f->height;
+
+ /* Do the voodoo which means "I'm changing lots of things, don't try to
+ refigure sizes until I'm done." */
+ lw_refigure_widget (x->column_widget, False);
+
+ /* the order in which children are managed is the top to
+ bottom order in which they are displayed in the paned window.
+ First, remove the text-area widget.
+ */
+ XtUnmanageChild (x->edit_widget);
+
+ /* remove the menubar that is there now, and put up the menubar that
+ should be there.
+ */
+ if (menubar_changed)
{
- BLOCK_INPUT;
- lw_destroy_all_widgets (id);
- UNBLOCK_INPUT;
+ XtManageChild (x->menubar_widget);
+ XtMapWidget (x->menubar_widget);
+ XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, 0);
}
+
+ /* Re-manage the text-area widget, and then thrash the sizes. */
+ XtManageChild (x->edit_widget);
+ lw_refigure_widget (x->column_widget, True);
+
+ /* Force the pane widget to resize itself with the right values. */
+ EmacsFrameSetCharSize (x->edit_widget, columns, rows);
+
+ UNBLOCK_INPUT;
}
-/* Called from Fx_create_frame to create the inital menubar of a frame
- before it is mapped, so that the window is mapped with the menubar already
- there instead of us tacking it on later and thrashing the window after it
- is visible. */
+
+/* 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
-initialize_frame_menubar (f)
+set_frame_menubar (f, first_time, deep_p)
FRAME_PTR f;
+ int first_time;
+ int deep_p;
{
- set_frame_menubar (f, 1);
-}
-\f
-/* Horizontal bounds of the current menu bar item. */
+ Widget menubar_widget = f->output_data.x->menubar_widget;
+ Lisp_Object tail, items, frame;
+ widget_value *wv, *first_wv, *prev_wv = 0;
+ int i;
+ LWLIB_ID id;
-static int this_menu_bar_item_beg;
-static int this_menu_bar_item_end;
+ if (f->output_data.x->id == 0)
+ f->output_data.x->id = next_menubar_widget_id++;
+ id = f->output_data.x->id;
-/* Horizontal position of the end of the last menu bar item. */
+ if (! menubar_widget)
+ deep_p = 1;
-static int last_menu_bar_item_end;
+ wv = malloc_widget_value ();
+ wv->name = "menubar";
+ wv->value = 0;
+ wv->enabled = 1;
+ first_wv = wv;
-/* Nonzero if position X, Y is in the menu bar and in some menu bar item
- but not in the current menu bar item. */
+ if (deep_p)
+ {
+ /* 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);
+ }
-static int
-other_menu_bar_item_p (f, x, y)
- FRAME_PTR f;
- int x, y;
-{
- return (y >= 0
- && y < f->display.x->menubar_widget->core.height
- && x >= 0
- && x < last_menu_bar_item_end
- && (x >= this_menu_bar_item_end
- || x < this_menu_bar_item_beg));
+ set_buffer_internal_1 (XBUFFER (buffer));
+
+ /* 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));
+
+ items = FRAME_MENU_BAR_ITEMS (f);
+
+ inhibit_garbage_collection ();
+
+ /* 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);
+
+ /* 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. */
+
+ 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;
+ }
+ }
+
+ /* Create or update the menu bar widget. */
+
+ BLOCK_INPUT;
+
+ if (menubar_widget)
+ {
+ /* Disable resizing (done for Motif!) */
+ lw_allow_resizing (f->output_data.x->widget, False);
+
+ /* 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, deep_p);
+
+ /* Re-enable the edit widget to resize. */
+ lw_allow_resizing (f->output_data.x->widget, True);
+ }
+ else
+ {
+ menubar_widget = lw_create_widget ("menubar", "menubar", id, first_wv,
+ f->output_data.x->column_widget,
+ 0,
+ popup_activate_callback,
+ menubar_selection_callback,
+ popup_deactivate_callback);
+ f->output_data.x->menubar_widget = menubar_widget;
+ }
+
+ {
+ int menubar_size
+ = (f->output_data.x->menubar_widget
+ ? (f->output_data.x->menubar_widget->core.height
+ + f->output_data.x->menubar_widget->core.border_width)
+ : 0);
+
+ if (FRAME_EXTERNAL_MENU_BAR (f))
+ {
+ Dimension ibw = 0;
+ XtVaGetValues (f->output_data.x->column_widget,
+ XtNinternalBorderWidth, &ibw, NULL);
+ menubar_size += ibw;
+ }
+
+ f->output_data.x->menubar_height = menubar_size;
+ }
+
+ free_menubar_widget_value_tree (first_wv);
+
+ update_frame_menubar (f);
+
+ UNBLOCK_INPUT;
}
-/* Unread a button-press event in the menu bar of frame F
- at x position XPOS relative to the inside of the frame. */
+/* Called from Fx_create_frame to create the inital menubar of a frame
+ before it is mapped, so that the window is mapped with the menubar already
+ there instead of us tacking it on later and thrashing the window after it
+ is visible. */
-static void
-unread_menu_bar_button (f, xpos)
+void
+initialize_frame_menubar (f)
FRAME_PTR f;
- int xpos;
{
- XEvent event;
-
- event.type = ButtonPress;
- event.xbutton.display = x_current_display;
- event.xbutton.serial = 0;
- event.xbutton.send_event = 0;
- event.xbutton.time = CurrentTime;
- event.xbutton.button = Button1;
- event.xbutton.window = XtWindow (f->display.x->menubar_widget);
- event.xbutton.x = xpos;
- XPutBackEvent (XDISPLAY &event);
+ /* 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, 1);
}
-/* If the mouse has moved to another menu bar item,
- return 1 and unread a button press event for that item.
- Otherwise return 0. */
+/* Get rid of the menu bar of frame F, and free its storage.
+ This is used when deleting a frame, and when turning off the menu bar. */
-static int
-check_mouse_other_menu_bar (f)
+void
+free_frame_menubar (f)
FRAME_PTR f;
{
- FRAME_PTR new_f;
- Lisp_Object bar_window;
- int part;
- Lisp_Object x, y;
- unsigned long time;
-
- (*mouse_position_hook) (&new_f, &bar_window, &part, &x, &y, &time);
+ Widget menubar_widget;
+ int id;
- if (f == new_f && other_menu_bar_item_p (f, x, y))
+ menubar_widget = f->output_data.x->menubar_widget;
+
+ if (menubar_widget)
{
- unread_menu_bar_button (f, x);
- return 1;
+ BLOCK_INPUT;
+ lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
+ UNBLOCK_INPUT;
}
-
- return 0;
}
+
#endif /* USE_X_TOOLKIT */
\f
/* xmenu_show actually displays a menu using the panes and items in menu_items
/* 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 the click that asked for 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
and perhaps also the pane's prefix.
#ifdef USE_X_TOOLKIT
-extern unsigned int x_mouse_grabbed;
-extern Lisp_Object Vmouse_depressed;
+/* We need a unique id for each widget handled by the Lucid Widget
+ library.
+
+ For the main windows, and popup menus, we use this counter,
+ which we increment each time after use. This starts from 1<<16.
+
+ For menu bars, we use numbers starting at 0, counted in
+ next_menubar_widget_id. */
+LWLIB_ID widget_id_tick;
+
+#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)
+ Widget widget;
+ LWLIB_ID id;
+ XtPointer client_data;
+{
+ menu_item_selection = (Lisp_Object *) client_data;
+}
static Lisp_Object
-xmenu_show (f, x, y, menubarp, keymaps, title, error)
+xmenu_show (f, x, y, for_click, keymaps, title, error)
FRAME_PTR f;
int x;
int y;
- int menubarp;
+ int for_click;
int keymaps;
Lisp_Object title;
char **error;
{
int i;
- int menu_id;
+ LWLIB_ID menu_id;
Widget menu;
- XlwMenuWidget menubar = (XlwMenuWidget) f->display.x->menubar_widget;
-
- /* This is the menu bar item (if any) that led to this menu. */
- widget_value *menubar_item = 0;
-
+ Arg av[2];
+ int ac = 0;
widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
widget_value **submenu_stack
= (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
Lisp_Object *subprefix_stack
= (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
int submenu_depth = 0;
+ XButtonPressedEvent dummy;
- /* 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;
+ int next_release_must_exit = 0;
*error = NULL;
- this_menu_bar_item_beg = -1;
- this_menu_bar_item_end = -1;
- last_menu_bar_item_end = -1;
-
- /* Figure out which menu bar item, if any, this menu is for. */
- if (menubarp)
+ if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
{
- int xbeg;
- int xend = 0;
-
- for (menubar_item = menubar->menu.old_stack[0]->contents;
- menubar_item;
- menubar_item = menubar_item->next)
- {
- xbeg = xend;
- xend += (string_width (menubar, menubar_item->name)
- + 2 * (menubar->menu.horizontal_spacing
- + menubar->menu.shadow_thickness));
- if (x >= xbeg && x < xend)
- {
- x = xbeg + 4;
- y = 0;
- /* Arrange to show a different menu if we move in the menu bar
- to a different item. */
- this_menu_bar_item_beg = xbeg;
- this_menu_bar_item_end = xend;
- }
- }
- last_menu_bar_item_end = xend;
+ *error = "Empty menu";
+ return Qnil;
}
- if (menubar_item == 0)
- menubarp = 0;
-
- /* Offset the coordinates to root-relative. */
- XtTranslateCoords (f->display.x->widget,
- x, y + f->display.x->menubar_widget->core.height,
- &root_x, &root_y);
- x = root_x;
- y = root_y;
/* Create a tree of widget_value objects
representing the panes and their items. */
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
{
/* Create a new item within current pane. */
- Lisp_Object item_name, enable, descrip;
+ Lisp_Object item_name, enable, descrip, def;
item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
descrip
= XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
+ def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION];
wv = malloc_widget_value ();
if (prev_wv)
if (!NILP (descrip))
wv->key = (char *) XSTRING (descrip)->data;
wv->value = 0;
- wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
+ /* If this item has a null value,
+ make the call_data null so that it won't display a box
+ when the mouse is on it. */
+ wv->call_data
+ = (!NILP (def) ? (void *) &XVECTOR (menu_items)->contents[i] : 0);
wv->enabled = !NILP (enable);
prev_wv = wv;
}
}
+ /* Deal with the title, if it is non-nil. */
+ if (!NILP (title))
+ {
+ widget_value *wv_title = malloc_widget_value ();
+ widget_value *wv_sep1 = malloc_widget_value ();
+ widget_value *wv_sep2 = malloc_widget_value ();
+
+ wv_sep2->name = "--";
+ wv_sep2->next = first_wv->contents;
+
+ wv_sep1->name = "--";
+ wv_sep1->next = wv_sep2;
+
+ wv_title->name = (char *) XSTRING (title)->data;
+ wv_title->enabled = True;
+ wv_title->next = wv_sep1;
+ first_wv->contents = wv_title;
+ }
+
/* Actually create the menu. */
- menu_id = ++popup_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_down_callback);
- /* Free the widget_value objects we used to specify the contents. */
- free_menubar_widget_value_tree (first_wv);
+ f->output_data.x->widget, 1, 0,
+ popup_selection_callback,
+ popup_deactivate_callback);
- /* No selection has been chosen yet. */
- menu_item_selection = 0;
+ /* Adjust coordinates to relative to the outer (window manager) window. */
+ {
+ Window child;
+ int win_x = 0, win_y = 0;
- /* If the mouse moves out of the menu before we show the menu,
- don't show it at all. */
- if (check_mouse_other_menu_bar (f))
- {
- lw_destroy_all_widgets (menu_id);
- return Qnil;
- }
+ /* Find the position of the outside upper-left corner of
+ the inner window, with respect to the outer window. */
+ if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
+ {
+ BLOCK_INPUT;
+ XTranslateCoordinates (FRAME_X_DISPLAY (f),
+ /* From-window, to-window. */
+ f->output_data.x->window_desc,
+ f->output_data.x->parent_desc,
- /* Highlight the menu bar item (if any) that led to this menu. */
- if (menubarp)
- {
- menubar_item->call_data = (XtPointer) 1;
- dispatch_dummy_expose (f->display.x->menubar_widget, x, y);
- }
+ /* From-position, to-position. */
+ 0, 0, &win_x, &win_y,
- /* Display the menu. */
- {
- XButtonPressedEvent dummy;
- XlwMenuWidget mw;
-
- mw = (XlwMenuWidget) ((CompositeWidget)menu)->composite.children[0];
-
- dummy.type = ButtonPress;
- dummy.serial = 0;
- dummy.send_event = 0;
- dummy.display = XtDisplay (menu);
- dummy.window = XtWindow (XtParent (menu));
- dummy.time = CurrentTime;
- dummy.button = 0;
- dummy.x_root = x;
- dummy.y_root = y;
-
- /* We activate directly the lucid implementation. */
- pop_up_menu (mw, &dummy);
+ /* Child of window. */
+ &child);
+ UNBLOCK_INPUT;
+ x += win_x;
+ y += win_y;
+ }
}
- /* No need to check a second time since this is done in the XEvent loop.
- This slows done the execution. */
-#if 0
- /* 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. */
- XtUngrabPointer ((Widget)
- ((XlwMenuWidget)
- ((CompositeWidget)menu)->composite.children[0]),
- CurrentTime);
- lw_destroy_all_widgets (menu_id);
- goto pop_down;
- }
-#endif
+ /* Adjust coordinates to be root-window-relative. */
+ x += f->output_data.x->left_pos;
+ y += f->output_data.x->top_pos;
- /* Process events that apply to the menu. */
- while (1)
- {
- XEvent event;
+ dummy.type = ButtonPress;
+ dummy.serial = 0;
+ dummy.send_event = 0;
+ dummy.display = FRAME_X_DISPLAY (f);
+ dummy.time = CurrentTime;
+ dummy.button = 0;
+ dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window;
+ dummy.window = dummy.root;
+ dummy.subwindow = dummy.root;
+ dummy.x_root = x;
+ dummy.y_root = y;
+ dummy.x = x;
+ dummy.y = y;
- XtAppNextEvent (Xt_app_con, &event);
- if (event.type == ButtonRelease)
- {
- XtDispatchEvent (&event);
- if (! menubarp)
- {
- /* 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;
- }
- break;
- }
- else if (event.type == Expose)
- process_expose_from_menu (event);
- else if (event.type == MotionNotify)
- {
- int event_x = (event.xmotion.x_root
- - (f->display.x->widget->core.x
- + f->display.x->widget->core.border_width));
- int event_y = (event.xmotion.y_root
- - (f->display.x->widget->core.y
- + f->display.x->widget->core.border_width));
-
- if (other_menu_bar_item_p (f, event_x, event_y))
- {
- /* The mouse moved into a different menu bar item.
- We should bring up that item's menu instead.
- First pop down this menu. */
- XtUngrabPointer ((Widget)
- ((XlwMenuWidget)
- ((CompositeWidget)menu)->composite.children[0]),
- event.xbutton.time);
- lw_destroy_all_widgets (menu_id);
-
- /* Put back an event that will bring up the other item's menu. */
- unread_menu_bar_button (f, event_x);
- /* Don't let us select anything in this case. */
- menu_item_selection = 0;
- break;
- }
- }
+ /* Don't allow any geometry request from the user. */
+ XtSetArg (av[ac], XtNgeometry, 0); ac++;
+ XtSetValues (menu, av, ac);
- XtDispatchEvent (&event);
- if (XtWindowToWidget(XDISPLAY event.xany.window) != menu)
- {
- queue_tmp
- = (struct event_queue *) malloc (sizeof (struct event_queue));
+ /* Free the widget_value objects we used to specify the contents. */
+ free_menubar_widget_value_tree (first_wv);
- if (queue_tmp != NULL)
- {
- queue_tmp->event = event;
- queue_tmp->next = queue;
- queue = queue_tmp;
- }
- }
- }
+ /* No selection has been chosen yet. */
+ menu_item_selection = 0;
- pop_down:
- /* Unhighlight the menu bar item (if any) that led to this menu. */
- if (menubarp)
- {
- menubar_item->call_data = (XtPointer) 0;
- dispatch_dummy_expose (f->display.x->menubar_widget, x, y);
- }
+ /* Display the menu. */
+ lw_popup_menu (menu, &dummy);
+ popup_activated_flag = 1;
+
+ /* Process events that apply to the menu. */
+ popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id);
/* 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 (XDISPLAY &queue_tmp->event);
- queue = queue_tmp->next;
- free ((char *)queue_tmp);
- }
-
/* 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;
if (!NILP (prefix))
entry = Fcons (prefix, entry);
for (j = submenu_depth - 1; j >= 0; j--)
- entry = Fcons (subprefix_stack[j], entry);
+ if (!NILP (subprefix_stack[j]))
+ entry = Fcons (subprefix_stack[j], entry);
}
return entry;
}
return Qnil;
}
+\f
+static void
+dialog_selection_callback (widget, id, client_data)
+ Widget widget;
+ LWLIB_ID id;
+ XtPointer client_data;
+{
+ /* 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 [] = {
"button1", "button2", "button3", "button4", "button5",
"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;
- XlwMenuWidget menubar = (XlwMenuWidget) f->display.x->menubar_widget;
char dialog_name[6];
- /* This is the menu bar item (if any) that led to this menu. */
- widget_value *menubar_item = 0;
-
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 = ++popup_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,
+ f->output_data.x->widget, 1, 0,
dialog_selection_callback, 0);
-#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);
/* 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(XDISPLAY event.xany.window) != menu)
- {
- 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;
- }
- }
- }
- pop_down:
+ popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id);
- /* Unread any events that we got but did not handle. */
- while (queue != NULL)
- {
- queue_tmp = queue;
- XPutBackEvent (XDISPLAY &queue_tmp->event);
- queue = queue_tmp->next;
- free ((char *)queue_tmp);
- }
+ 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, keymaps, title, error)
+xmenu_show (f, x, y, for_click, keymaps, title, error)
FRAME_PTR f;
int x, y;
+ int for_click;
int keymaps;
- int menubarp;
Lisp_Object title;
char **error;
{
if (menu_items_n_panes == 0)
return Qnil;
+ if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
+ {
+ *error = "Empty menu";
+ return Qnil;
+ }
+
/* Figure out which root window F is on. */
- XGetGeometry (x_current_display, FRAME_X_WINDOW (f), &root,
+ XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
&dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
&dummy_uint, &dummy_uint);
/* Make the menu on that window. */
- menu = XMenuCreate (XDISPLAY root, "emacs");
+ menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
if (menu == NULL)
{
*error = "Can't create menu";
return Qnil;
}
+#ifdef HAVE_X_WINDOWS
/* Adjust coordinates to relative to the outer (window manager) window. */
-#ifdef HAVE_X11
{
Window child;
int win_x = 0, win_y = 0;
/* Find the position of the outside upper-left corner of
the inner window, with respect to the outer window. */
- if (f->display.x->parent_desc != ROOT_WINDOW)
+ if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
{
BLOCK_INPUT;
- XTranslateCoordinates (x_current_display,
+ XTranslateCoordinates (FRAME_X_DISPLAY (f),
/* From-window, to-window. */
- f->display.x->window_desc,
- f->display.x->parent_desc,
+ f->output_data.x->window_desc,
+ f->output_data.x->parent_desc,
/* From-position, to-position. */
0, 0, &win_x, &win_y,
y += win_y;
}
}
-#endif /* HAVE_X11 */
+#endif /* HAVE_X_WINDOWS */
/* Adjust coordinates to be root-window-relative. */
- x += f->display.x->left_pos;
- y += f->display.x->top_pos;
+ x += f->output_data.x->left_pos;
+ y += f->output_data.x->top_pos;
/* Create all the necessary panes and their items. */
i = 0;
if (keymaps && !NILP (prefix))
pane_string++;
- lpane = XMenuAddPane (XDISPLAY menu, pane_string, TRUE);
+ lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, TRUE);
if (lpane == XM_FAILURE)
{
- XMenuDestroy (XDISPLAY menu);
+ XMenuDestroy (FRAME_X_DISPLAY (f), menu);
*error = "Can't create pane";
return Qnil;
}
else
item_data = XSTRING (item_name)->data;
- if (XMenuAddSelection (XDISPLAY menu, lpane, 0, item_data,
+ if (XMenuAddSelection (FRAME_X_DISPLAY (f),
+ menu, lpane, 0, item_data,
!NILP (enable))
== XM_FAILURE)
{
- XMenuDestroy (XDISPLAY menu);
+ XMenuDestroy (FRAME_X_DISPLAY (f), menu);
*error = "Can't add selection to menu";
return Qnil;
}
}
/* All set and ready to fly. */
- XMenuRecompute (XDISPLAY menu);
- dispwidth = DisplayWidth (x_current_display, XDefaultScreen (x_current_display));
- dispheight = DisplayHeight (x_current_display, XDefaultScreen (x_current_display));
+ XMenuRecompute (FRAME_X_DISPLAY (f), menu);
+ dispwidth = DisplayWidth (FRAME_X_DISPLAY (f),
+ XScreenNumberOfScreen (FRAME_X_SCREEN (f)));
+ dispheight = DisplayHeight (FRAME_X_DISPLAY (f),
+ XScreenNumberOfScreen (FRAME_X_SCREEN (f)));
x = min (x, dispwidth);
y = min (y, dispheight);
x = max (x, 1);
y = max (y, 1);
- XMenuLocate (XDISPLAY menu, 0, 0, x, y,
+ XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
&ulx, &uly, &width, &height);
if (ulx+width > dispwidth)
{
XMenuSetFreeze (menu, TRUE);
pane = selidx = 0;
- status = XMenuActivate (XDISPLAY menu, &pane, &selidx,
+ status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
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 (FRAME_X_DISPLAY_INFO (f));
+#endif
+
switch (status)
{
case XM_SUCCESS:
break;
case XM_FAILURE:
- XMenuDestroy (XDISPLAY menu);
*error = "Can't activate menu";
case XM_IA_SELECT:
case XM_NO_SELECT:
entry = Qnil;
break;
}
- XMenuDestroy (XDISPLAY menu);
+ XMenuDestroy (FRAME_X_DISPLAY (f), menu);
+
+#ifdef HAVE_X_WINDOWS
+ /* State that no mouse buttons are now held.
+ (The oldXMenu code doesn't track this info for us.)
+ That is not necessarily true, but the fiction leads to reasonable
+ results, and it is a pain to ask which are actually held now. */
+ FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
+#endif
+
return entry;
}
+
#endif /* not USE_X_TOOLKIT */
\f
syms_of_xmenu ()
staticpro (&menu_items);
menu_items = Qnil;
- popup_id_tick = (1<<16);
+ Qdebug_on_next_call = intern ("debug-on-next-call");
+ staticpro (&Qdebug_on_next_call);
+
+#ifdef USE_X_TOOLKIT
+ widget_id_tick = (1<<16);
+ next_menubar_widget_id = 1;
+#endif
+
defsubr (&Sx_popup_menu);
defsubr (&Sx_popup_dialog);
}