A single vector slot containing lambda indicates the end of a submenu.
The submenu follows a menu item which is the way to reach the submenu.
+ A single vector slot containing quote indicates that the
+ following items should appear on the right of a dialog box.
+
Using a Lisp vector to hold this information while we decode it
takes care of protecting all the data from GC. */
menu_items_submenu_depth--;
}
+/* Indicate boundary between left and right. */
+
+static void
+push_left_right_boundary ()
+{
+ if (menu_items_used + 1 > menu_items_allocated)
+ grow_menu_items ();
+
+ XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
+}
+
/* Start a new menu pane in menu_items..
NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */
item = Fcar (tail);
if (STRINGP (item))
push_menu_item (item, Qnil, Qnil, Qnil);
+ else if (NILP (item))
+ push_left_right_boundary ();
else
{
CHECK_CONS (item, 0);
"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\
f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
xpos = (FONT_WIDTH (f->display.x->font) * XWINDOW (window)->left);
- ypos = (FONT_HEIGHT (f->display.x->font) * XWINDOW (window)->top);
+ ypos = (f->display.x->line_height * XWINDOW (window)->top);
}
else
/* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
CONTENTS specifies the alternatives to display in the dialog box.\n\
It is a list of the form (TITLE ITEM1 ITEM2...).\n\
Each ITEM is a cons cell (STRING . VALUE).\n\
-The return value is VALUE from the chosen item.")
+The return value is VALUE from the chosen item.\n\n\
+An ITEM may also be just a string--that makes a nonselectable item.\n\
+An ITEM may also be nil--that means to put all preceding items\n\
+on the left of the dialog box and all following items on the right.\n\
+\(By default, approximately half appear on each side.)")
(position, contents)
Lisp_Object position, contents;
{
/* Decode the first argument: find the window or frame to use. */
if (EQ (position, Qt))
{
+#if 0 /* Using the frame the mouse is on may not be right. */
/* Use the mouse's current position. */
FRAME_PTR new_f = 0;
Lisp_Object bar_window;
XSET (window, Lisp_Frame, new_f);
else
window = selected_window;
+#endif
+ /* Decode the first argument: find the window and the coordinates. */
+ if (EQ (position, Qt))
+ window = selected_window;
}
else if (CONSP (position))
{
dummy.x = x;
dummy.y = y;
- XtDispatchEvent (&dummy);
+ XtDispatchEvent ((XEvent *) &dummy);
}
static int
extern void EmacsFrameSetCharSize ();
static void
-update_one_frame_psheets (f)
+update_frame_menubar (f)
FRAME_PTR f;
{
struct x_display *x = f->display.x;
}
void
-set_frame_menubar (f)
+set_frame_menubar (f, first_time)
FRAME_PTR f;
+ int first_time;
{
Widget menubar_widget = f->display.x->menubar_widget;
int id = (int) f;
wv->enabled = 1;
save_wv = first_wv = wv;
- items = FRAME_MENU_BAR_ITEMS (f);
+ 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)
{
prev_wv->next = wv;
else
save_wv->contents = wv;
- wv->name = XSTRING (string)->data;
+ wv->name = (char *) XSTRING (string)->data;
wv->value = 0;
wv->enabled = 1;
prev_wv = wv;
free_menubar_widget_value_tree (first_wv);
- update_one_frame_psheets (f);
+ /* Don't update the menubar the first time it is created via x_window. */
+ if (!first_time)
+ update_frame_menubar (f);
UNBLOCK_INPUT;
}
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);
+}
\f
-/* Nonzero if position X, Y relative to inside of frame F
- is in some other menu bar item. */
+/* Horizontal bounds of the current menu bar item. */
static int this_menu_bar_item_beg;
static int this_menu_bar_item_end;
+/* Horizontal position of the end of the last menu bar item. */
+
+static int last_menu_bar_item_end;
+
+/* Nonzero if position X, Y is in the menu bar and in some menu bar item
+ but not in the current menu bar item. */
+
static int
other_menu_bar_item_p (f, x, y)
FRAME_PTR f;
return (y >= 0
&& y < f->display.x->menubar_widget->core.height
&& x >= 0
- && x < f->display.x->menubar_widget->core.width
+ && x < last_menu_bar_item_end
&& (x >= this_menu_bar_item_end
|| x < this_menu_bar_item_beg));
}
struct event_queue *queue = NULL;
struct event_queue *queue_tmp;
+ Position root_x, root_y;
+
*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)
xend += (string_width (menubar, menubar_item->name)
+ 2 * (menubar->menu.horizontal_spacing
+ menubar->menu.shadow_thickness));
- if (x < xend)
+ if (x >= xbeg && x < xend)
{
x = xbeg + 4;
y = 0;
to a different item. */
this_menu_bar_item_beg = xbeg;
this_menu_bar_item_end = xend;
- break;
}
}
+ last_menu_bar_item_end = xend;
}
if (menubar_item == 0)
menubarp = 0;
/* Offset the coordinates to root-relative. */
- x += (f->display.x->widget->core.x
- + f->display.x->widget->core.border_width);
- y += (f->display.x->widget->core.y
- + f->display.x->widget->core.border_width
- + f->display.x->menubar_widget->core.height);
+ XtTranslateCoords (f->display.x->widget,
+ x, y + f->display.x->menubar_widget->core.height,
+ &root_x, &root_y);
+ x = root_x;
+ y = root_y;
/* Create a tree of widget_value objects
representing the panes and their items. */
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. */
prev_wv->next = wv;
else
save_wv->contents = wv;
- wv->name = XSTRING (item_name)->data;
+ wv->name = (char *) XSTRING (item_name)->data;
if (!NILP (descrip))
- wv->key = XSTRING (descrip)->data;
+ wv->key = (char *) XSTRING (descrip)->data;
wv->value = 0;
wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
wv->enabled = !NILP (enable);
dispatch_dummy_expose (f->display.x->menubar_widget, x, y);
}
-#if 0 /* No need to do that. The menu has disappeared. */
+ /* 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. */
lw_destroy_all_widgets (menu_id);
-#endif
/* Unread any events that we got but did not handle. */
while (queue != NULL)
XPutBackEvent (XDISPLAY &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
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;
}
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. */
+ int boundary_seen = 0;
+
*error = NULL;
if (menu_items_n_panes > 1)
*error = "Submenu in dialog items";
return Qnil;
}
+ if (EQ (item_name, Qquote))
+ {
+ /* This is the boundary between left-side elts
+ and right-side elts. Stop incrementing right_count. */
+ boundary_seen = 1;
+ i++;
+ continue;
+ }
if (nb_buttons >= 10)
{
free_menubar_widget_value_tree (first_wv);
prev_wv->next = wv;
wv->name = (char *) button_names[nb_buttons];
if (!NILP (descrip))
- wv->key = XSTRING (descrip)->data;
- wv->value = XSTRING (item_name)->data;
+ wv->key = (char *) XSTRING (descrip)->data;
+ wv->value = (char *) XSTRING (item_name)->data;
wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
wv->enabled = !NILP (enable);
prev_wv = wv;
+ if (! boundary_seen)
+ left_count++;
+
nb_buttons++;
i += MENU_ITEMS_ITEM_LENGTH;
}
+ /* If the boundary was not specified,
+ by default put half on the left and half on the right. */
+ if (! boundary_seen)
+ left_count = nb_buttons - nb_buttons / 2;
+
wv = malloc_widget_value ();
wv->name = dialog_name;
dialog_name[1] = '0' + nb_buttons;
dialog_name[2] = 'B';
dialog_name[3] = 'R';
- dialog_name[4] = '0' + nb_buttons / 2;
+ /* Number of buttons to put on the right. */
+ dialog_name[4] = '0' + nb_buttons - left_count;
dialog_name[5] = 0;
wv->contents = first_wv;
first_wv = wv;
-
}
/* Actually create the dialog. */
}
pop_down:
+ /* 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. */
+ x_mouse_grabbed = 0;
+
/* Unread any events that we got but did not handle. */
while (queue != NULL)
{
XPutBackEvent (XDISPLAY &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
char *datap;
int ulx, uly, width, height;
int dispwidth, dispheight;
- int i;
+ int i, j;
+ int maxwidth;
int dummy_int;
unsigned int dummy_uint;
return Qnil;
}
i += MENU_ITEMS_PANE_LENGTH;
+
+ /* Find the width of the widest item in this pane. */
+ maxwidth = 0;
+ j = i;
+ while (j < menu_items_used)
+ {
+ Lisp_Object item;
+ item = XVECTOR (menu_items)->contents[j];
+ if (EQ (item, Qt))
+ break;
+ if (NILP (item))
+ {
+ j++;
+ continue;
+ }
+ width = XSTRING (item)->size;
+ if (width > maxwidth)
+ maxwidth = width;
+
+ j += MENU_ITEMS_ITEM_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
{
/* Create a new item within current pane. */
Lisp_Object item_name, enable, descrip;
+ unsigned char *item_data;
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];
if (!NILP (descrip))
- item_name = concat2 (item_name, descrip);
+ {
+ int gap = maxwidth - XSTRING (item_name)->size;
+#ifdef C_ALLOCA
+ Lisp_Object spacer;
+ spacer = Fmake_string (make_number (gap), make_number (' '));
+ item_name = concat2 (item_name, spacer);
+ item_name = concat2 (item_name, descrip);
+ item_data = XSTRING (item_name)->data;
+#else
+ /* if alloca is fast, use that to make the space,
+ to reduce gc needs. */
+ item_data
+ = (unsigned char *) alloca (maxwidth
+ + XSTRING (descrip)->size + 1);
+ bcopy (XSTRING (item_name)->data, item_data,
+ XSTRING (item_name)->size);
+ for (j = XSTRING (item_name)->size; j < maxwidth; j++)
+ item_data[j] = ' ';
+ bcopy (XSTRING (descrip)->data, item_data + j,
+ XSTRING (descrip)->size);
+ item_data[j + XSTRING (descrip)->size] = 0;
+#endif
+ }
+ else
+ item_data = XSTRING (item_name)->data;
- if (XMenuAddSelection (XDISPLAY menu, lpane, 0,
- XSTRING (item_name)->data,
+ if (XMenuAddSelection (XDISPLAY menu, lpane, 0, item_data,
!NILP (enable))
== XM_FAILURE)
{
i += MENU_ITEMS_ITEM_LENGTH;
}
}
-
+
/* All set and ready to fly. */
XMenuRecompute (XDISPLAY menu);
dispwidth = DisplayWidth (x_current_display, XDefaultScreen (x_current_display));
}
if (ulx < 0) x -= ulx;
if (uly < 0) y -= uly;
-
+
+ XMenuSetAEQ (menu, TRUE);
XMenuSetFreeze (menu, TRUE);
pane = selidx = 0;
break;
}
XMenuDestroy (XDISPLAY menu);
+
+ /* 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. */
+ x_mouse_grabbed = 0;
+
return entry;
}
#endif /* not USE_X_TOOLKIT */