mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-02-17 18:37:33 +00:00
(widget_id_tick): Renamed from popup_id_tick.
(popup_get_selection, popup_activated, popup_activate_callback, menubar_selection_callback, popup_deactivate_callback, single_submenu): New or replaced functions. (popup_activated_flag): New variable. (dispatch_dummy_expose, event_is_in_menu_item, map_event_to_object): Removed. (update_frame_menubar): Use lw_refigure_widget to provide widget set independence. (set_frame_menubar): Use lw_allow_resizing to control unsightly Motif menubar resizing in a widget set independent fashion. (xmenu_show): Removed menubar handling code, since that is now done in lwlib. Display a popup menu title centered and followed by two separators. Use lw_popup_menu() to display the menu. Use popup_get_selection() to deal with X11 event handling while the menu is posted.
This commit is contained in:
parent
a263cd2dd9
commit
4dedbfe0bf
1 changed files with 388 additions and 354 deletions
742
src/xmenu.c
742
src/xmenu.c
|
|
@ -66,9 +66,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
#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 */
|
||||
|
||||
#define min(x,y) (((x) < (y)) ? (x) : (y))
|
||||
|
|
@ -85,8 +83,10 @@ extern Display *x_current_display;
|
|||
#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;
|
||||
/* 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. */
|
||||
LWLIB_ID widget_id_tick;
|
||||
|
||||
extern Lisp_Object Qmenu_enable;
|
||||
extern Lisp_Object Qmenu_bar;
|
||||
|
|
@ -96,6 +96,7 @@ extern void process_expose_from_menu ();
|
|||
extern XtAppContext Xt_app_con;
|
||||
|
||||
static Lisp_Object xdialog_show ();
|
||||
void popup_get_selection ();
|
||||
#endif
|
||||
|
||||
static Lisp_Object xmenu_show ();
|
||||
|
|
@ -151,6 +152,11 @@ static int menu_items_n_panes;
|
|||
/* 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;
|
||||
|
||||
|
||||
/* Initialize the menu_items structure if we haven't already done so.
|
||||
Also mark it as currently empty. */
|
||||
|
||||
|
|
@ -994,122 +1000,148 @@ on the left of the dialog box and all following items on the right.\n\
|
|||
|
||||
#ifdef USE_X_TOOLKIT
|
||||
|
||||
static void
|
||||
dispatch_dummy_expose (w, x, y)
|
||||
Widget w;
|
||||
int x;
|
||||
int y;
|
||||
/* Loop in Xt until the menu pulldown or dialog popup has been
|
||||
popped down (deactivated). */
|
||||
void
|
||||
popup_get_selection (initial_event)
|
||||
XEvent *initial_event;
|
||||
{
|
||||
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;
|
||||
XEvent event;
|
||||
|
||||
XtDispatchEvent ((XEvent *) &dummy);
|
||||
}
|
||||
if (initial_event)
|
||||
event = *initial_event;
|
||||
else
|
||||
XtAppNextEvent (Xt_app_con, &event);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* Return the menu bar key which corresponds to event EVENT in frame F. */
|
||||
|
||||
Lisp_Object
|
||||
map_event_to_object (event, f)
|
||||
struct input_event *event;
|
||||
FRAME_PTR f;
|
||||
{
|
||||
int i,j, string_w;
|
||||
window_state* ws;
|
||||
XlwMenuWidget mw = (XlwMenuWidget) f->display.x->menubar_widget;
|
||||
widget_value *val;
|
||||
|
||||
|
||||
string_w = 0;
|
||||
/* Find the window */
|
||||
for (val = mw->menu.old_stack [0]->contents; val; val = val->next)
|
||||
while (1)
|
||||
{
|
||||
ws = &mw->menu.windows [0];
|
||||
if (ws && event_is_in_menu_item (mw, event, val->name, &string_w))
|
||||
BLOCK_INPUT;
|
||||
XtDispatchEvent (&event);
|
||||
UNBLOCK_INPUT;
|
||||
if (!popup_activated())
|
||||
break;
|
||||
XtAppNextEvent (Xt_app_con, &event);
|
||||
}
|
||||
}
|
||||
|
||||
/* Detect if a dialog or menu has been posted. */
|
||||
int
|
||||
popup_activated ()
|
||||
{
|
||||
return popup_activated_flag;
|
||||
}
|
||||
|
||||
|
||||
/* This callback is invoked when the user selects a menubar cascade
|
||||
pushbutton, but before the pulldown menu is posted. */
|
||||
|
||||
static void
|
||||
popup_activate_callback (widget, id, client_data)
|
||||
Widget widget;
|
||||
LWLIB_ID id;
|
||||
XtPointer 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
|
||||
menubar_selection_callback (widget, id, client_data)
|
||||
Widget widget;
|
||||
LWLIB_ID id;
|
||||
XtPointer client_data;
|
||||
{
|
||||
Lisp_Object prefix;
|
||||
FRAME_PTR f = (FRAME_PTR) 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)
|
||||
{
|
||||
Lisp_Object entry;
|
||||
|
||||
if (EQ (XVECTOR (vector)->contents[i], Qnil))
|
||||
{
|
||||
Lisp_Object items;
|
||||
int i;
|
||||
|
||||
items = FRAME_MENU_BAR_ITEMS (f);
|
||||
|
||||
for (i = 0; i < XVECTOR (items)->size; i += 3)
|
||||
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];
|
||||
if ((int) client_data == i)
|
||||
{
|
||||
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;
|
||||
int j;
|
||||
struct input_event buf;
|
||||
|
||||
if (!strcmp (val->name, XSTRING (string)->data))
|
||||
return item;
|
||||
buf.kind = menu_bar_event;
|
||||
buf.frame_or_window = Qmenu_bar;
|
||||
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];
|
||||
kbd_buffer_store_event (&buf);
|
||||
}
|
||||
|
||||
if (!NILP (prefix))
|
||||
{
|
||||
buf.kind = menu_bar_event;
|
||||
buf.frame_or_window = prefix;
|
||||
kbd_buffer_store_event (&buf);
|
||||
}
|
||||
|
||||
buf.kind = menu_bar_event;
|
||||
buf.frame_or_window = entry;
|
||||
kbd_buffer_store_event (&buf);
|
||||
|
||||
return;
|
||||
}
|
||||
i += MENU_ITEMS_ITEM_LENGTH;
|
||||
}
|
||||
}
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
#ifdef __STDC__
|
||||
static Lisp_Object *volatile menu_item_selection;
|
||||
#else
|
||||
static Lisp_Object *menu_item_selection;
|
||||
#endif
|
||||
/* This callback is invoked when a dialog or menu is finished being
|
||||
used and has been unposted. */
|
||||
|
||||
static void
|
||||
popup_selection_callback (widget, id, client_data)
|
||||
popup_deactivate_callback (widget, id, client_data)
|
||||
Widget widget;
|
||||
LWLIB_ID id;
|
||||
XtPointer client_data;
|
||||
{
|
||||
menu_item_selection = (Lisp_Object *) client_data;
|
||||
popup_activated_flag = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
popup_down_callback (widget, id, client_data)
|
||||
Widget widget;
|
||||
LWLIB_ID id;
|
||||
XtPointer client_data;
|
||||
{
|
||||
BLOCK_INPUT;
|
||||
lw_destroy_all_widgets (id);
|
||||
UNBLOCK_INPUT;
|
||||
}
|
||||
|
||||
static void
|
||||
dialog_selection_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;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
|
@ -1136,9 +1168,149 @@ free_menubar_widget_value_tree (wv)
|
|||
free_widget_value (wv);
|
||||
UNBLOCK_INPUT;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
static widget_value *
|
||||
single_submenu (item_key, item_name, maps)
|
||||
Lisp_Object item_key, item_name, maps;
|
||||
{
|
||||
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;
|
||||
|
||||
length = Flength (maps);
|
||||
len = XINT (length);
|
||||
|
||||
/* Convert the list MAPS into a vector MAPVEC. */
|
||||
mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
mapvec[i] = Fcar (maps);
|
||||
maps = Fcdr (maps);
|
||||
}
|
||||
|
||||
menu_items_n_panes = 0;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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 = "menu";
|
||||
wv->value = 0;
|
||||
wv->enabled = 1;
|
||||
first_wv = wv;
|
||||
save_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)
|
||||
{
|
||||
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;
|
||||
if (!NILP (prefix))
|
||||
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;
|
||||
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];
|
||||
|
||||
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;
|
||||
wv->call_data = (void *) i;
|
||||
wv->enabled = !NILP (enable);
|
||||
prev_wv = wv;
|
||||
|
||||
i += MENU_ITEMS_ITEM_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
return first_wv;
|
||||
}
|
||||
|
||||
extern void EmacsFrameSetCharSize ();
|
||||
|
||||
/* Recompute the menu bar of frame F. */
|
||||
|
||||
static void
|
||||
update_frame_menubar (f)
|
||||
FRAME_PTR f;
|
||||
|
|
@ -1147,6 +1319,12 @@ update_frame_menubar (f)
|
|||
int columns, rows;
|
||||
int menubar_changed;
|
||||
|
||||
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));
|
||||
|
||||
|
|
@ -1159,9 +1337,10 @@ update_frame_menubar (f)
|
|||
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);
|
||||
|
||||
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.
|
||||
|
|
@ -1178,12 +1357,9 @@ update_frame_menubar (f)
|
|||
XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Re-manage the text-area widget */
|
||||
/* Re-manage the text-area widget, and then thrash the sizes. */
|
||||
XtManageChild (x->edit_widget);
|
||||
|
||||
/* and now thrash the sizes */
|
||||
XawPanedSetRefigureMode (x->column_widget, 1);
|
||||
lw_refigure_widget (x->column_widget, True);
|
||||
|
||||
/* Force the pane widget to resize itself with the right values. */
|
||||
EmacsFrameSetCharSize (x->edit_widget, columns, rows);
|
||||
|
|
@ -1209,44 +1385,59 @@ set_frame_menubar (f, first_time)
|
|||
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));
|
||||
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)
|
||||
{
|
||||
Lisp_Object string;
|
||||
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 = malloc_widget_value ();
|
||||
wv = single_submenu (key, string, maps);
|
||||
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;
|
||||
}
|
||||
|
||||
finish_menu_items ();
|
||||
|
||||
f->menu_bar_vector = menu_items;
|
||||
f->menu_bar_items_used = menu_items_used;
|
||||
menu_items = Qnil;
|
||||
|
||||
if (menubar_widget)
|
||||
lw_modify_all_widgets (id, first_wv, False);
|
||||
{
|
||||
/* Disable resizing (done for Motif!) */
|
||||
lw_allow_resizing (f->display.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);
|
||||
|
||||
/* Re-enable the edit widget to resize. */
|
||||
lw_allow_resizing (f->display.x->widget, True);
|
||||
}
|
||||
else
|
||||
{
|
||||
menubar_widget = lw_create_widget ("menubar", "menubar",
|
||||
id, first_wv,
|
||||
f->display.x->column_widget,
|
||||
0, 0,
|
||||
0, 0);
|
||||
f->display.x->column_widget,
|
||||
0,
|
||||
popup_activate_callback,
|
||||
menubar_selection_callback,
|
||||
popup_deactivate_callback);
|
||||
f->display.x->menubar_widget = menubar_widget;
|
||||
XtVaSetValues (menubar_widget,
|
||||
XtNshowGrip, 0,
|
||||
XtNresizeToPreferred, 1,
|
||||
XtNallowResize, 1,
|
||||
0);
|
||||
}
|
||||
|
||||
free_menubar_widget_value_tree (first_wv);
|
||||
|
|
@ -1258,6 +1449,24 @@ set_frame_menubar (f, first_time)
|
|||
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. */
|
||||
|
||||
void
|
||||
initialize_frame_menubar (f)
|
||||
FRAME_PTR f;
|
||||
{
|
||||
/* This function is called before the first chance to redisplay
|
||||
the frame. It has to be, so the frame will have the right size. */
|
||||
FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
|
||||
set_frame_menubar (f, 1);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
void
|
||||
free_frame_menubar (f)
|
||||
FRAME_PTR f;
|
||||
|
|
@ -1275,16 +1484,6 @@ free_frame_menubar (f)
|
|||
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. */
|
||||
void
|
||||
initialize_frame_menubar (f)
|
||||
FRAME_PTR f;
|
||||
{
|
||||
set_frame_menubar (f, 1);
|
||||
}
|
||||
|
||||
/* Horizontal bounds of the current menu bar item. */
|
||||
|
||||
|
|
@ -1383,12 +1582,28 @@ extern Lisp_Object Vdouble_click_time;
|
|||
extern unsigned int x_mouse_grabbed;
|
||||
extern Lisp_Object Vmouse_depressed;
|
||||
|
||||
#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)
|
||||
FRAME_PTR f;
|
||||
int x;
|
||||
int y;
|
||||
int menubarp;
|
||||
int menubarp; /* Dummy parameter for Xt version of
|
||||
xmenu_show() */
|
||||
int keymaps;
|
||||
Lisp_Object title;
|
||||
char **error;
|
||||
|
|
@ -1396,13 +1611,8 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
|
|||
int i;
|
||||
int menu_id;
|
||||
Widget menu;
|
||||
XlwMenuWidget menubar = (XlwMenuWidget) f->display.x->menubar_widget;
|
||||
Arg av [2];
|
||||
int ac = 0;
|
||||
|
||||
/* This is the menu bar item (if any) that led to this menu. */
|
||||
widget_value *menubar_item = 0;
|
||||
|
||||
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 *));
|
||||
|
|
@ -1433,48 +1643,6 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
|
|||
*error = "Empty menu";
|
||||
return Qnil;
|
||||
}
|
||||
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)
|
||||
{
|
||||
int xbeg;
|
||||
int xend = 0;
|
||||
widget_value *mb_item = 0;
|
||||
|
||||
for (mb_item = menubar->menu.old_stack[0]->contents;
|
||||
mb_item;
|
||||
mb_item = mb_item->next)
|
||||
{
|
||||
xbeg = xend;
|
||||
xend += (string_width (menubar, mb_item->name)
|
||||
+ 2 * (menubar->menu.horizontal_spacing
|
||||
+ menubar->menu.shadow_thickness));
|
||||
if (x >= xbeg && x < xend)
|
||||
{
|
||||
x = xbeg + 4;
|
||||
y = 0;
|
||||
menubar_item = mb_item;
|
||||
/* 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;
|
||||
}
|
||||
if (menubar_item == 0)
|
||||
menubarp = 0;
|
||||
|
||||
/* Offset the coordinates to root-relative. */
|
||||
if (f->display.x->menubar_widget != 0)
|
||||
y += f->display.x->menubar_widget->core.height;
|
||||
XtTranslateCoords (f->display.x->widget,
|
||||
x, y, &root_x, &root_y);
|
||||
x = root_x;
|
||||
y = root_y;
|
||||
|
||||
/* Create a tree of widget_value objects
|
||||
representing the panes and their items. */
|
||||
|
|
@ -1577,11 +1745,31 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
|
|||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
popup_selection_callback,
|
||||
popup_deactivate_callback);
|
||||
|
||||
/* Don't allow any geometry request from the user. */
|
||||
XtSetArg (av[ac], XtNgeometry, 0); ac++;
|
||||
|
|
@ -1593,42 +1781,9 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
|
|||
/* No selection has been chosen yet. */
|
||||
menu_item_selection = 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;
|
||||
}
|
||||
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
lw_popup_menu (menu);
|
||||
popup_activated_flag = 1;
|
||||
|
||||
/* No need to check a second time since this is done in the XEvent loop.
|
||||
This slows done the execution. */
|
||||
|
|
@ -1639,143 +1794,15 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
|
|||
/* The mouse moved into a different menu bar item.
|
||||
We should bring up that item's menu instead.
|
||||
First pop down this menu. */
|
||||
#if 0 /* xlwmenu.c now does this. */
|
||||
XtUngrabPointer ((Widget)
|
||||
((XlwMenuWidget)
|
||||
((CompositeWidget)menu)->composite.children[0]),
|
||||
CurrentTime);
|
||||
#endif
|
||||
lw_destroy_all_widgets (menu_id);
|
||||
goto pop_down;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Process events that apply to the menu. */
|
||||
while (1)
|
||||
{
|
||||
XEvent event;
|
||||
int queue_and_exit = 0;
|
||||
int in_this_menu = 0, in_menu_bar = 0;
|
||||
Widget widget;
|
||||
|
||||
XtAppNextEvent (Xt_app_con, &event);
|
||||
|
||||
/* Check whether the event happened in the menu
|
||||
or any child of it. */
|
||||
widget = XtWindowToWidget (XDISPLAY event.xany.window);
|
||||
|
||||
while (widget)
|
||||
{
|
||||
if (widget == menu)
|
||||
{
|
||||
in_this_menu = 1;
|
||||
break;
|
||||
}
|
||||
if (widget == f->display.x->menubar_widget)
|
||||
{
|
||||
in_menu_bar = 1;
|
||||
break;
|
||||
}
|
||||
widget = XtParent (widget);
|
||||
}
|
||||
|
||||
if (event.type == ButtonRelease)
|
||||
{
|
||||
/* Do the work of construct_mouse_click since it can't
|
||||
be called. Initially, the popup menu has been called
|
||||
from a ButtonPress in the edit_widget. Then the mouse
|
||||
has been set to grabbed. Reset it now. */
|
||||
x_mouse_grabbed &= ~(1 << event.xbutton.button);
|
||||
if (!x_mouse_grabbed)
|
||||
Vmouse_depressed = Qnil;
|
||||
|
||||
/* If we release the button soon without selecting anything,
|
||||
stay in the loop--that is, leave the menu posted.
|
||||
Otherwise, exit this loop and thus pop down the menu. */
|
||||
if (! in_this_menu
|
||||
&& (next_release_must_exit
|
||||
|| !(((XButtonEvent *) (&event))->time - last_event_timestamp
|
||||
< XINT (Vdouble_click_time))))
|
||||
break;
|
||||
}
|
||||
/* A button press outside the menu => pop it down. */
|
||||
else if (event.type == ButtonPress && !in_this_menu)
|
||||
break;
|
||||
else if (event.type == ButtonPress)
|
||||
next_release_must_exit = 1;
|
||||
else if (event.type == KeyPress)
|
||||
{
|
||||
/* Exit the loop, but first queue this event for reuse. */
|
||||
queue_and_exit = 1;
|
||||
}
|
||||
else if (event.type == Expose)
|
||||
process_expose_from_menu (event);
|
||||
/* If the mouse moves to a different menu bar item, switch to
|
||||
that item's menu. But only if the button is still held down. */
|
||||
else if (event.type == MotionNotify
|
||||
&& x_mouse_grabbed)
|
||||
{
|
||||
int event_x = (event.xmotion.x_root
|
||||
- (f->display.x->widget->core.x
|
||||
+ 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. */
|
||||
#if 0 /* xlwmenu.c now does this. */
|
||||
XtUngrabPointer ((Widget)
|
||||
((XlwMenuWidget)
|
||||
((CompositeWidget)menu)->composite.children[0]),
|
||||
event.xbutton.time);
|
||||
#endif
|
||||
lw_destroy_all_widgets (menu_id);
|
||||
|
||||
/* Put back an event that will bring up the other item's menu. */
|
||||
unread_menu_bar_button (f, event_x);
|
||||
/* Don't let us select anything in this case. */
|
||||
menu_item_selection = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (event.type == UnmapNotify)
|
||||
{
|
||||
/* If the menu disappears, there is no need to stay in the
|
||||
loop. */
|
||||
if (event.xunmap.window == menu->core.window)
|
||||
break;
|
||||
}
|
||||
|
||||
XtDispatchEvent (&event);
|
||||
|
||||
if (queue_and_exit || (!in_this_menu && !in_menu_bar))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (queue_and_exit)
|
||||
break;
|
||||
}
|
||||
popup_get_selection ((XEvent *) 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);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
|
@ -1848,6 +1875,19 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
|
|||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static void
|
||||
dialog_selection_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;
|
||||
}
|
||||
|
||||
static char * button_names [] = {
|
||||
"button1", "button2", "button3", "button4", "button5",
|
||||
|
|
@ -1864,12 +1904,8 @@ xdialog_show (f, menubarp, keymaps, title, error)
|
|||
int i, nb_buttons=0;
|
||||
int 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
|
||||
|
|
@ -1987,13 +2023,10 @@ xdialog_show (f, menubarp, keymaps, title, error)
|
|||
}
|
||||
|
||||
/* 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,
|
||||
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, True);
|
||||
/* Free the widget_value objects we used to specify the contents. */
|
||||
free_menubar_widget_value_tree (first_wv);
|
||||
|
|
@ -2355,6 +2388,7 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
|
|||
|
||||
return entry;
|
||||
}
|
||||
|
||||
#endif /* not USE_X_TOOLKIT */
|
||||
|
||||
syms_of_xmenu ()
|
||||
|
|
@ -2362,7 +2396,7 @@ syms_of_xmenu ()
|
|||
staticpro (&menu_items);
|
||||
menu_items = Qnil;
|
||||
|
||||
popup_id_tick = (1<<16);
|
||||
widget_id_tick = (1<<16);
|
||||
defsubr (&Sx_popup_menu);
|
||||
defsubr (&Sx_popup_dialog);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue