#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
#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"
#define FALSE 0
#endif /* no TRUE */
+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;
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. */
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;
- 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);
+ 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 (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;
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, &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
}
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 (CONSP (tem) && EQ (Fcar (tem), Qmenu_bar))
- menubarp = 1;
}
}
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,
/* 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)
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;
+ }
+}
+
+/* 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->output_data.x->saved_button_event->type != ButtonPress)
+ return;
+
+ set_frame_menubar (f, 0, 1);
+
+ BLOCK_INPUT;
+ XtDispatchEvent ((XEvent *) f->output_data.x->saved_button_event);
+ UNBLOCK_INPUT;
+
+ /* Ignore this if we get it a second time. */
+ f->output_data.x->saved_button_event->type = 0;
}
/* 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 = menubar_id_to_frame (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 if (EQ (XVECTOR (vector)->contents[i], Qt))
{
- prefix
- = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
+ prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
i += MENU_ITEMS_PANE_LENGTH;
}
else
{
- entry
- = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
- if ((int) client_data == i)
+ 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 = 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 (subprefix_stack[j]))
{
buf.kind = menu_bar_event;
- buf.frame_or_window = subprefix_stack[j];
+ 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 = prefix;
+ buf.frame_or_window = Fcons (frame, prefix);
kbd_buffer_store_event (&buf);
}
buf.kind = menu_bar_event;
- buf.frame_or_window = entry;
+ buf.frame_or_window = Fcons (frame, entry);
kbd_buffer_store_event (&buf);
return;
widget_value **submenu_stack;
int mapno;
int previous_items = menu_items_used;
+ int top_level_items = 0;
length = Flength (maps);
len = XINT (length);
/* 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++)
- single_keymap_panes (mapvec[i], item_name, item_key, 0);
+ {
+ 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);
+ }
/* Create a tree of widget_value objects
representing the panes and their items. */
wv->enabled = 1;
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.
else
first_wv->contents = wv;
wv->name = pane_string;
- if (!NILP (prefix))
+ /* 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;
wv = malloc_widget_value ();
if (prev_wv)
prev_wv->next = wv;
- else
+ else
save_wv->contents = wv;
+
wv->name = (char *) XSTRING (item_name)->data;
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;
}
}
+ /* 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 ();
-/* 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)
FRAME_PTR f;
{
- struct x_display *x = f->display.x;
+ struct x_output *x = f->output_data.x;
int columns, rows;
int menubar_changed;
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)
+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;
- int id = (int) f;
- Lisp_Object tail, items;
+ 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;
- BLOCK_INPUT;
+ if (f->output_data.x->id == 0)
+ f->output_data.x->id = next_menubar_widget_id++;
+ id = f->output_data.x->id;
+
+ 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);
- 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));
+
+ 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)
+ /* 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
{
- Lisp_Object string;
- string = XVECTOR (items)->contents[i + 1];
- if (NILP (string))
- break;
- wv->name = (char *) XSTRING (string)->data;
- wv = wv->next;
+ /* 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;
+ }
}
- finish_menu_items ();
+ /* Create or update the menu bar widget. */
- f->menu_bar_vector = menu_items;
- f->menu_bar_items_used = menu_items_used;
- menu_items = Qnil;
+ BLOCK_INPUT;
if (menubar_widget)
{
/* Disable resizing (done for Motif!) */
- lw_allow_resizing (f->display.x->widget, False);
+ 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, 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);
+ lw_allow_resizing (f->output_data.x->widget, True);
}
else
{
- menubar_widget = lw_create_widget ("menubar", "menubar",
- id, first_wv,
- f->display.x->column_widget,
+ 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->display.x->menubar_widget = menubar_widget;
+ 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);
- /* 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);
UNBLOCK_INPUT;
}
/* 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.
Widget menubar_widget;
int id;
- menubar_widget = f->display.x->menubar_widget;
- id = (int) f;
+ menubar_widget = f->output_data.x->menubar_widget;
if (menubar_widget)
{
BLOCK_INPUT;
- lw_destroy_all_widgets (id);
+ lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
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 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
/* 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. 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
-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; /* 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];
+ Arg av[2];
int ac = 0;
widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
widget_value **submenu_stack
Lisp_Object *subprefix_stack
= (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;
+ XButtonPressedEvent dummy;
int first_pane;
int next_release_must_exit = 0;
}
/* 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,
+ f->output_data.x->widget, 1, 0,
popup_selection_callback,
popup_deactivate_callback);
+ /* Adjust coordinates to relative to the outer (window manager) window. */
+ {
+ 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->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,
+
+ /* From-position, to-position. */
+ 0, 0, &win_x, &win_y,
+
+ /* Child of window. */
+ &child);
+ UNBLOCK_INPUT;
+ x += win_x;
+ y += win_y;
+ }
+ }
+
+ /* Adjust coordinates to be root-window-relative. */
+ x += f->output_data.x->left_pos;
+ y += f->output_data.x->top_pos;
+
+ 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;
+
/* Don't allow any geometry request from the user. */
XtSetArg (av[ac], XtNgeometry, 0); ac++;
XtSetValues (menu, av, ac);
menu_item_selection = 0;
/* Display the menu. */
- lw_popup_menu (menu);
+ lw_popup_menu (menu, &dummy);
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,
+ f->output_data.x->widget, 1, 0,
dialog_selection_callback, 0);
lw_modify_all_widgets (dialog_id, first_wv->contents, True);
/* Free the widget_value objects we used to specify the contents. */
/* 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));
-
- 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
+ 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 (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, 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;
{
/* 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 != FRAME_X_DISPLAY_INFO (f)->root_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->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,
#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;
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)
{
staticpro (&menu_items);
menu_items = Qnil;
+ 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);