X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/fc932ac6c7b54ac6f79222a2548707a97d3a44f4..f47a9ec42bfe64c316473c64c847922bbbce2063:/src/xmenu.c diff --git a/src/xmenu.c b/src/xmenu.c index 1e6b0b13f1..f3e27be222 100644 --- a/src/xmenu.c +++ b/src/xmenu.c @@ -1,5 +1,5 @@ /* X Communication module for terminals which understand the X protocol. - Copyright (C) 1986, 1988, 1993, 1994, 1996 Free Software Foundation, Inc. + Copyright (C) 1986, 88, 93, 94, 96, 99, 2000 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -30,16 +30,17 @@ Boston, MA 02111-1307, USA. */ /* Rewritten for clarity and GC protection by rms in Feb 94. */ +#include + /* On 4.3 this loses if it comes after xterm.h. */ #include -#include #include #include "lisp.h" #include "termhooks.h" +#include "keyboard.h" #include "frame.h" #include "window.h" -#include "keyboard.h" #include "blockinput.h" #include "buffer.h" @@ -62,6 +63,7 @@ Boston, MA 02111-1307, USA. */ #include "dispextern.h" #ifdef HAVE_X_WINDOWS +#undef HAVE_MULTILINGUAL_MENU #ifdef USE_X_TOOLKIT #include #include @@ -77,6 +79,10 @@ Boston, MA 02111-1307, USA. */ #endif /* not USE_X_TOOLKIT */ #endif /* HAVE_X_WINDOWS */ +#ifdef USE_MOTIF +#include /* for LESSTIF_VERSION */ +#endif + #define min(x,y) (((x) < (y)) ? (x) : (y)) #define max(x,y) (((x) > (y)) ? (x) : (y)) @@ -110,6 +116,16 @@ static Lisp_Object xdialog_show (); void popup_get_selection (); #endif +#ifdef USE_X_TOOLKIT + +/* Define HAVE_BOXES if meus can handle radio and toggle buttons. */ + +#define HAVE_BOXES 1 +#endif + +static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object, + Lisp_Object, Lisp_Object, Lisp_Object, + Lisp_Object, Lisp_Object)); static Lisp_Object xmenu_show (); static void keymap_panes (); static void single_keymap_panes (); @@ -143,12 +159,18 @@ static void list_of_items (); #define MENU_ITEMS_PANE_PREFIX 2 #define MENU_ITEMS_PANE_LENGTH 3 -#define MENU_ITEMS_ITEM_NAME 0 -#define MENU_ITEMS_ITEM_ENABLE 1 -#define MENU_ITEMS_ITEM_VALUE 2 -#define MENU_ITEMS_ITEM_EQUIV_KEY 3 -#define MENU_ITEMS_ITEM_DEFINITION 4 -#define MENU_ITEMS_ITEM_LENGTH 5 +enum menu_item_idx +{ + MENU_ITEMS_ITEM_NAME = 0, + MENU_ITEMS_ITEM_ENABLE, + MENU_ITEMS_ITEM_VALUE, + MENU_ITEMS_ITEM_EQUIV_KEY, + MENU_ITEMS_ITEM_DEFINITION, + MENU_ITEMS_ITEM_TYPE, + MENU_ITEMS_ITEM_SELECTED, + MENU_ITEMS_ITEM_HELP, + MENU_ITEMS_ITEM_LENGTH +}; static Lisp_Object menu_items; @@ -167,7 +189,7 @@ 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; +int popup_activated_flag; static int next_menubar_widget_id; @@ -191,13 +213,13 @@ menubar_id_to_frame (id) Lisp_Object tail, frame; FRAME_PTR f; - for (tail = Vframe_list; GC_CONSP (tail); tail = XCONS (tail)->cdr) + for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail)) { - frame = XCONS (tail)->car; + frame = XCAR (tail); if (!GC_FRAMEP (frame)) continue; f = XFRAME (frame); - if (f->output_data.nothing == 1) + if (!FRAME_WINDOW_P (f)) continue; if (f->output_data.x->id == id) return f; @@ -314,17 +336,17 @@ push_menu_pane (name, prefix_vec) XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec; } -/* 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, 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). */ +/* 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, 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). TYPE is the type of this menu + item, one of nil, `toggle' or `radio'. */ static void -push_menu_item (name, enable, key, def, equiv) - Lisp_Object name, enable, key, def, equiv; +push_menu_item (name, enable, key, def, equiv, type, selected, help) + Lisp_Object name, enable, key, def, equiv, type, selected, help; { if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated) grow_menu_items (); @@ -334,6 +356,9 @@ push_menu_item (name, enable, key, def, equiv) XVECTOR (menu_items)->contents[menu_items_used++] = key; XVECTOR (menu_items)->contents[menu_items_used++] = equiv; XVECTOR (menu_items)->contents[menu_items_used++] = def; + XVECTOR (menu_items)->contents[menu_items_used++] = type; + XVECTOR (menu_items)->contents[menu_items_used++] = selected; + XVECTOR (menu_items)->contents[menu_items_used++] = help; } /* Look through KEYMAPS, a vector of keymaps that is NMAPS long, @@ -355,7 +380,8 @@ keymap_panes (keymaps, nmaps, notreal) But don't make a pane that is empty--ignore that map instead. P is the number of panes we have made so far. */ for (mapno = 0; mapno < nmaps; mapno++) - single_keymap_panes (keymaps[mapno], Qnil, Qnil, notreal, 10); + single_keymap_panes (keymaps[mapno], + map_prompt (keymaps[mapno]), Qnil, notreal, 10); finish_menu_items (); } @@ -395,14 +421,14 @@ single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth) notbuttons = menu_items_used; #endif - for (tail = keymap; CONSP (tail); tail = XCONS (tail)->cdr) + for (tail = keymap; CONSP (tail); tail = XCDR (tail)) { GCPRO2 (keymap, pending_maps); /* Look at each key binding, and if it is a menu item add it to this menu. */ - item = XCONS (tail)->car; + item = XCAR (tail); if (CONSP (item)) - single_menu_item (XCONS (item)->car, XCONS (item)->cdr, + single_menu_item (XCAR (item), XCDR (item), &pending_maps, notreal, maxdepth, ¬buttons); else if (VECTORP (item)) { @@ -425,12 +451,12 @@ single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth) { Lisp_Object elt, eltcdr, string; elt = Fcar (pending_maps); - eltcdr = XCONS (elt)->cdr; - string = XCONS (eltcdr)->car; + eltcdr = XCDR (elt); + string = XCAR (eltcdr); /* We no longer discard the @ from the beginning of the string here. Instead, we do this in xmenu_show. */ single_keymap_panes (Fcar (elt), string, - XCONS (eltcdr)->cdr, notreal, maxdepth - 1); + XCDR (eltcdr), notreal, maxdepth - 1); pending_maps = Fcdr (pending_maps); } } @@ -455,7 +481,7 @@ single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth, int maxdepth, notreal; int *notbuttons_ptr; { - Lisp_Object def, map, item_string, enabled; + Lisp_Object map, item_string, enabled; struct gcpro gcpro1, gcpro2; int res; @@ -560,7 +586,10 @@ single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth, push_menu_item (item_string, enabled, key, XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF], - XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ]); + XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ], + XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE], + XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED], + XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]); #ifdef USE_X_TOOLKIT /* Display a submenu using the toolkit. */ @@ -612,7 +641,7 @@ list_of_items (pane) { item = Fcar (tail); if (STRINGP (item)) - push_menu_item (item, Qnil, Qnil, Qt, Qnil); + push_menu_item (item, Qnil, Qnil, Qt, Qnil, Qnil, Qnil, Qnil); else if (NILP (item)) push_left_right_boundary (); else @@ -620,7 +649,7 @@ list_of_items (pane) CHECK_CONS (item, 0); item1 = Fcar (item); CHECK_STRING (item1, 1); - push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil); + push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil, Qnil, Qnil, Qnil); } } } @@ -661,14 +690,12 @@ cached information about equivalent key sequences.") (position, menu) Lisp_Object position, menu; { - int number_of_panes, panes; Lisp_Object keymap, tem; - int xpos, ypos; + int xpos = 0, ypos = 0; Lisp_Object title; char *error_name; Lisp_Object selection; - int i, j; - FRAME_PTR f; + struct frame *f = NULL; Lisp_Object x, y, window; int keymaps = 0; int for_click = 0; @@ -681,12 +708,13 @@ cached information about equivalent key sequences.") /* Decode the first argument: find the window and the coordinates. */ if (EQ (position, Qt) - || (CONSP (position) && EQ (XCONS (position)->car, Qmenu_bar))) + || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar) + || EQ (XCAR (position), Qtool_bar)))) { /* Use the mouse's current position. */ - FRAME_PTR new_f = selected_frame; + FRAME_PTR new_f = SELECTED_FRAME (); Lisp_Object bar_window; - int part; + enum scroll_bar_part part; unsigned long time; if (mouse_position_hook) @@ -760,15 +788,11 @@ cached information about equivalent key sequences.") /* Decode the menu items from what was specified. */ - keymap = Fkeymapp (menu); - tem = Qnil; - if (CONSP (menu)) - tem = Fkeymapp (Fcar (menu)); - if (!NILP (keymap)) + keymap = get_keymap (menu, 0, 0); + if (CONSP (keymap)) { /* We were given a keymap. Extract menu info from the keymap. */ Lisp_Object prompt; - keymap = get_keymap (menu); /* Extract the detailed info to make one pane. */ keymap_panes (&menu, 1, NILP (position)); @@ -785,7 +809,7 @@ cached information about equivalent key sequences.") keymaps = 1; } - else if (!NILP (tem)) + else if (CONSP (menu) && KEYMAPP (XCAR (menu))) { /* We were given a list of keymaps. */ int nmaps = XFASTINT (Flength (menu)); @@ -801,7 +825,7 @@ cached information about equivalent key sequences.") { Lisp_Object prompt; - maps[i++] = keymap = get_keymap (Fcar (tem)); + maps[i++] = keymap = get_keymap (Fcar (tem), 1, 0); prompt = map_prompt (keymap); if (NILP (title) && !NILP (prompt)) @@ -872,18 +896,19 @@ on the left of the dialog box and all following items on the right.\n\ (position, contents) Lisp_Object position, contents; { - FRAME_PTR f; + struct frame * f = NULL; Lisp_Object window; check_x (); /* Decode the first argument: find the window or frame to use. */ if (EQ (position, Qt) - || (CONSP (position) && EQ (XCONS (position)->car, Qmenu_bar))) + || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar) + || EQ (XCAR (position), Qtool_bar)))) { #if 0 /* Using the frame the mouse is on may not be right. */ /* Use the mouse's current position. */ - FRAME_PTR new_f = selected_frame; + FRAME_PTR new_f = SELECTED_FRAME (); Lisp_Object bar_window; int part; unsigned long time; @@ -1025,8 +1050,12 @@ popup_get_selection (initial_event, dpyinfo, id) else if (event.type == KeyPress && dpyinfo->display == event.xbutton.display) { - popup_activated_flag = 0; - break; + KeySym keysym = XLookupKeysym (&event.xkey, 0); + if (!IsModifierKey (keysym)) + { + popup_activated_flag = 0; + break; + } } /* Button presses outside the menu also pop it down. */ else if (event.type == ButtonPress @@ -1048,14 +1077,10 @@ popup_get_selection (initial_event, dpyinfo, id) && (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; - } + queue_tmp = (struct event_queue *) xmalloc (sizeof *queue_tmp); + queue_tmp->event = event; + queue_tmp->next = queue; + queue = queue_tmp; } else XtDispatchEvent (&event); @@ -1071,7 +1096,7 @@ popup_get_selection (initial_event, dpyinfo, id) queue_tmp = queue; XPutBackEvent (queue_tmp->event.xany.display, &queue_tmp->event); queue = queue_tmp->next; - free ((char *)queue_tmp); + xfree ((char *)queue_tmp); /* Cause these events to get read as soon as we UNBLOCK_INPUT. */ interrupt_input_pending = 1; } @@ -1091,6 +1116,7 @@ popup_get_selection (initial_event, dpyinfo, id) passing it to the toolkit right away, is that we can safely execute Lisp code. */ +void x_activate_menubar (f) FRAME_PTR f; { @@ -1118,7 +1144,6 @@ 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. */ @@ -1128,7 +1153,72 @@ popup_activate_callback (widget, id, client_data) LWLIB_ID id; XtPointer client_data; { +#ifdef USE_MOTIF + ++popup_activated_flag; +#else popup_activated_flag = 1; +#endif +} + +/* This callback is invoked when a dialog or menu is finished being + used and has been unposted. */ + +static void +popup_deactivate_callback (widget, id, client_data) + Widget widget; + LWLIB_ID id; + XtPointer client_data; +{ +#ifdef USE_MOTIF + --popup_activated_flag; +#else + popup_activated_flag = 0; +#endif +} + +/* Lwlib callback called when menu items are highlighted/unhighlighted + while moving the mouse over them. WIDGET is the menu bar or menu + popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to + the widget_value structure for the menu item, or null in case of + unhighlighting. */ + +void +menu_highlight_callback (widget, id, call_data) + Widget widget; + LWLIB_ID id; + void *call_data; +{ + widget_value *wv = (widget_value *) call_data; + struct frame *f; + Lisp_Object frame, help; + + help = wv && wv->help ? build_string (wv->help) : Qnil; + + /* Determine the frame for the help event. */ + f = menubar_id_to_frame (id); + if (f) + { + XSETFRAME (frame, f); + kbd_buffer_store_help_event (frame, help); + } + else + { + /* WIDGET is the popup menu. It's parent is the frame's + widget. See which frame that is. */ + Widget frame_widget = XtParent (widget); + Lisp_Object tail; + + for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail)) + { + frame = XCAR (tail); + if (GC_FRAMEP (frame) + && (f = XFRAME (frame), + FRAME_X_P (f) && f->output_data.x->widget == frame_widget)) + break; + } + + show_help_echo (help, Qnil, Qnil, Qnil, 1); + } } /* This callback is called from the menu bar pulldown menu @@ -1151,6 +1241,7 @@ menubar_selection_callback (widget, id, client_data) if (!f) return; + entry = Qnil; subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object)); vector = f->menu_bar_vector; prefix = Qnil; @@ -1185,27 +1276,31 @@ menubar_selection_callback (widget, id, client_data) Lisp_Object frame; XSETFRAME (frame, f); - buf.kind = menu_bar_event; - buf.frame_or_window = Fcons (frame, Fcons (Qmenu_bar, Qnil)); + buf.kind = MENU_BAR_EVENT; + buf.frame_or_window = frame; + buf.arg = frame; 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]); + buf.kind = MENU_BAR_EVENT; + buf.frame_or_window = frame; + buf.arg = subprefix_stack[j]; kbd_buffer_store_event (&buf); } if (!NILP (prefix)) { - buf.kind = menu_bar_event; - buf.frame_or_window = Fcons (frame, prefix); + buf.kind = MENU_BAR_EVENT; + buf.frame_or_window = frame; + buf.arg = prefix; kbd_buffer_store_event (&buf); } - buf.kind = menu_bar_event; - buf.frame_or_window = Fcons (frame, entry); + buf.kind = MENU_BAR_EVENT; + buf.frame_or_window = frame; + buf.arg = entry; kbd_buffer_store_event (&buf); return; @@ -1215,18 +1310,6 @@ menubar_selection_callback (widget, id, client_data) } } -/* This callback is invoked when a dialog or menu is finished being - used and has been unposted. */ - -static void -popup_deactivate_callback (widget, id, client_data) - Widget widget; - LWLIB_ID id; - XtPointer client_data; -{ - popup_activated_flag = 0; -} - /* Allocate a widget_value, blocking input. */ widget_value * @@ -1284,7 +1367,6 @@ single_submenu (item_key, item_name, maps) int len; Lisp_Object *mapvec; widget_value **submenu_stack; - int mapno; int previous_items = menu_items_used; int top_level_items = 0; @@ -1306,14 +1388,14 @@ single_submenu (item_key, item_name, maps) for (i = 0; i < len; i++) { if (SYMBOLP (mapvec[i]) - || (CONSP (mapvec[i]) - && NILP (Fkeymapp (mapvec[i])))) + || (CONSP (mapvec[i]) && !KEYMAPP (mapvec[i]))) { /* Here we have a command at top level in the menu bar as opposed to a submenu. */ top_level_items = 1; push_menu_pane (Qnil, Qnil); - push_menu_item (item_name, Qt, item_key, mapvec[i], Qnil); + push_menu_item (item_name, Qt, item_key, mapvec[i], + Qnil, Qnil, Qnil, Qnil); } else single_keymap_panes (mapvec[i], item_name, item_key, 0, 10); @@ -1328,6 +1410,7 @@ single_submenu (item_key, item_name, maps) wv->name = "menu"; wv->value = 0; wv->enabled = 1; + wv->button_type = BUTTON_TYPE_NONE; first_wv = wv; save_wv = 0; prev_wv = 0; @@ -1366,6 +1449,10 @@ single_submenu (item_key, item_name, maps) char *pane_string; pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME]; prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; +#ifndef HAVE_MULTILINGUAL_MENU + if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) + pane_name = string_make_unibyte (pane_name); +#endif pane_string = (NILP (pane_name) ? "" : (char *) XSTRING (pane_name)->data); /* If there is just one top-level pane, put all its items directly @@ -1390,6 +1477,7 @@ single_submenu (item_key, item_name, maps) wv->name++; wv->value = 0; wv->enabled = 1; + wv->button_type = BUTTON_TYPE_NONE; } save_wv = wv; prev_wv = 0; @@ -1398,12 +1486,24 @@ single_submenu (item_key, item_name, maps) else { /* Create a new item within current pane. */ - Lisp_Object item_name, enable, descrip, def; + Lisp_Object item_name, enable, descrip, def, type, selected; + Lisp_Object help; + 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]; + type = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_TYPE]; + selected = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_SELECTED]; + help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP]; + +#ifndef HAVE_MULTILINGUAL_MENU + if (STRING_MULTIBYTE (item_name)) + item_name = string_make_unibyte (item_name); + if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) + descrip = string_make_unibyte (descrip); +#endif wv = xmalloc_widget_value (); if (prev_wv) @@ -1419,6 +1519,20 @@ single_submenu (item_key, item_name, maps) 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); + + if (NILP (type)) + wv->button_type = BUTTON_TYPE_NONE; + else if (EQ (type, QCradio)) + wv->button_type = BUTTON_TYPE_RADIO; + else if (EQ (type, QCtoggle)) + wv->button_type = BUTTON_TYPE_TOGGLE; + else + abort (); + + wv->selected = !NILP (selected); + if (STRINGP (help)) + wv->help = XSTRING (help)->data; + prev_wv = wv; i += MENU_ITEMS_ITEM_LENGTH; @@ -1450,8 +1564,6 @@ 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. @@ -1485,16 +1597,16 @@ update_frame_menubar (f) { XtManageChild (x->menubar_widget); XtMapWidget (x->menubar_widget); - XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, 0); + XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL); } /* Re-manage the text-area widget, and then thrash the sizes. */ XtManageChild (x->edit_widget); + x_set_menu_resources_from_menu_face (f, x->menubar_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; } @@ -1509,7 +1621,7 @@ set_frame_menubar (f, first_time, deep_p) int deep_p; { Widget menubar_widget = f->output_data.x->menubar_widget; - Lisp_Object tail, items, frame; + Lisp_Object items; widget_value *wv, *first_wv, *prev_wv = 0; int i; LWLIB_ID id; @@ -1536,6 +1648,7 @@ set_frame_menubar (f, first_time, deep_p) wv->name = "menubar"; wv->value = 0; wv->enabled = 1; + wv->button_type = BUTTON_TYPE_NONE; first_wv = wv; if (deep_p) @@ -1608,6 +1721,7 @@ set_frame_menubar (f, first_time, deep_p) first_wv->contents = wv; /* Don't set wv->name here; GC during the loop might relocate it. */ wv->enabled = 1; + wv->button_type = BUTTON_TYPE_NONE; prev_wv = wv; } @@ -1666,6 +1780,7 @@ set_frame_menubar (f, first_time, deep_p) wv->name = (char *) XSTRING (string)->data; wv->value = 0; wv->enabled = 1; + wv->button_type = BUTTON_TYPE_NONE; /* This prevents lwlib from assuming this menu item is really supposed to be empty. */ /* The EMACS_INT cast avoids a warning. @@ -1708,7 +1823,8 @@ set_frame_menubar (f, first_time, deep_p) 0, popup_activate_callback, menubar_selection_callback, - popup_deactivate_callback); + popup_deactivate_callback, + menu_highlight_callback); f->output_data.x->menubar_widget = menubar_widget; } @@ -1736,7 +1852,6 @@ set_frame_menubar (f, first_time, deep_p) } free_menubar_widget_value_tree (first_wv); - update_frame_menubar (f); UNBLOCK_INPUT; @@ -1765,7 +1880,6 @@ free_frame_menubar (f) FRAME_PTR f; { Widget menubar_widget; - int id; menubar_widget = f->output_data.x->menubar_widget; @@ -1809,11 +1923,7 @@ free_frame_menubar (f) 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) @@ -1848,7 +1958,6 @@ xmenu_show (f, x, y, for_click, keymaps, title, error) XButtonPressedEvent dummy; int first_pane; - int next_release_must_exit = 0; *error = NULL; @@ -1864,6 +1973,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error) wv->name = "menu"; wv->value = 0; wv->enabled = 1; + wv->button_type = BUTTON_TYPE_NONE; first_wv = wv; first_pane = 1; @@ -1900,6 +2010,10 @@ xmenu_show (f, x, y, for_click, keymaps, title, error) char *pane_string; pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME]; prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; +#ifndef HAVE_MULTILINGUAL_MENU + if (!NILP (pane_name) && STRING_MULTIBYTE (pane_name)) + pane_name = string_make_unibyte (pane_name); +#endif pane_string = (NILP (pane_name) ? "" : (char *) XSTRING (pane_name)->data); /* If there is just one top-level pane, put all its items directly @@ -1922,6 +2036,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error) wv->name++; wv->value = 0; wv->enabled = 1; + wv->button_type = BUTTON_TYPE_NONE; save_wv = wv; prev_wv = 0; } @@ -1936,13 +2051,23 @@ xmenu_show (f, x, y, for_click, keymaps, title, error) else { /* Create a new item within current pane. */ - Lisp_Object item_name, enable, descrip, def; + Lisp_Object item_name, enable, descrip, def, type, selected, help; 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]; - + type = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_TYPE]; + selected = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_SELECTED]; + help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP]; + +#ifndef HAVE_MULTILINGUAL_MENU + if (STRINGP (item_name) && STRING_MULTIBYTE (item_name)) + item_name = string_make_unibyte (item_name); + if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) + item_name = string_make_unibyte (descrip); +#endif + wv = xmalloc_widget_value (); if (prev_wv) prev_wv->next = wv; @@ -1958,6 +2083,20 @@ xmenu_show (f, x, y, for_click, keymaps, title, error) wv->call_data = (!NILP (def) ? (void *) &XVECTOR (menu_items)->contents[i] : 0); wv->enabled = !NILP (enable); + + if (NILP (type)) + wv->button_type = BUTTON_TYPE_NONE; + else if (EQ (type, QCtoggle)) + wv->button_type = BUTTON_TYPE_TOGGLE; + else if (EQ (type, QCradio)) + wv->button_type = BUTTON_TYPE_RADIO; + else + abort (); + + wv->selected = !NILP (selected); + if (STRINGP (help)) + wv->help = XSTRING (help)->data; + prev_wv = wv; i += MENU_ITEMS_ITEM_LENGTH; @@ -1977,8 +2116,13 @@ xmenu_show (f, x, y, for_click, keymaps, title, error) wv_sep1->name = "--"; wv_sep1->next = wv_sep2; +#ifndef HAVE_MULTILINGUAL_MENU + if (STRING_MULTIBYTE (title)) + title = string_make_unibyte (title); +#endif wv_title->name = (char *) XSTRING (title)->data; wv_title->enabled = True; + wv_title->button_type = BUTTON_TYPE_NONE; wv_title->next = wv_sep1; first_wv->contents = wv_title; } @@ -1988,7 +2132,8 @@ xmenu_show (f, x, y, for_click, keymaps, title, error) menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv, f->output_data.x->widget, 1, 0, popup_selection_callback, - popup_deactivate_callback); + popup_deactivate_callback, + menu_highlight_callback); /* Adjust coordinates to relative to the outer (window manager) window. */ { @@ -2046,16 +2191,30 @@ xmenu_show (f, x, y, for_click, keymaps, title, error) /* Free the widget_value objects we used to specify the contents. */ free_menubar_widget_value_tree (first_wv); + /* Override any default settings with ones from the `menu' face. */ + x_set_menu_resources_from_menu_face (f, menu); + /* No selection has been chosen yet. */ menu_item_selection = 0; /* Display the menu. */ - lw_popup_menu (menu, &dummy); + lw_popup_menu (menu, (XEvent *) &dummy); popup_activated_flag = 1; /* Process events that apply to the menu. */ popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id); +#ifdef LESSTIF_VERSION + /* Nov 1998: For an unknown reason a button grab remains active + after the popup menu has gone. */ + XUngrabButton (XtDisplay (f->output_data.x->widget), + AnyButton, AnyModifier, + XtWindow (f->output_data.x->widget)); + XUngrabButton (XtDisplay (f->output_data.x->edit_widget), + AnyButton, AnyModifier, + XtWindow (f->output_data.x->edit_widget)); +#endif /* LESSTIF_VERSION */ + /* fp turned off the following statement and wrote a comment that it is unnecessary--that the menu has already disappeared. Nowadays the menu disappears ok, all right, but @@ -2068,7 +2227,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error) { Lisp_Object prefix, entry; - prefix = Qnil; + prefix = entry = Qnil; i = 0; while (i < menu_items_used) { @@ -2152,7 +2311,7 @@ xdialog_show (f, keymaps, title, error) Widget menu; char dialog_name[6]; - widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; + widget_value *wv, *first_wv = 0, *prev_wv = 0; /* Number of elements seen so far, before boundary. */ int left_count = 0; @@ -2261,7 +2420,7 @@ xdialog_show (f, keymaps, title, error) dialog_id = widget_id_tick++; menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv, f->output_data.x->widget, 1, 0, - dialog_selection_callback, 0); + dialog_selection_callback, 0, 0); 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); @@ -2296,6 +2455,12 @@ xdialog_show (f, keymaps, title, error) = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; i += MENU_ITEMS_PANE_LENGTH; } + else if (EQ (XVECTOR (menu_items)->contents[i], Qquote)) + { + /* This is the boundary between left-side elts and + right-side elts. */ + ++i; + } else { entry @@ -2317,8 +2482,52 @@ xdialog_show (f, keymaps, title, error) return Qnil; } + #else /* not USE_X_TOOLKIT */ +/* The frame of the last activated non-toolkit menu bar. + Used to generate menu help events. */ + +static struct frame *menu_help_frame; + + +/* Show help HELP_STRING, or clear help if HELP_STRING is null. + + PANE is the pane number, and ITEM is the menu item number in + the menu (currently not used). + + This cannot be done with generating a HELP_EVENT because + XMenuActivate contains a loop that doesn't let Emacs process + keyboard events. */ + +static void +menu_help_callback (help_string, pane, item) + char *help_string; + int pane, item; +{ + extern Lisp_Object Qmenu_item; + Lisp_Object *first_item; + Lisp_Object pane_name; + Lisp_Object menu_object; + + first_item = XVECTOR (menu_items)->contents; + if (EQ (first_item[0], Qt)) + pane_name = first_item[MENU_ITEMS_PANE_NAME]; + else if (EQ (first_item[0], Qquote)) + /* This shouldn't happen, see xmenu_show. */ + pane_name = build_string (""); + else + pane_name = first_item[MENU_ITEMS_ITEM_NAME]; + + /* (menu-item MENU-NAME PANE-NUMBER) */ + menu_object = Fcons (Qmenu_item, + Fcons (pane_name, + Fcons (make_number (pane), Qnil))); + show_help_echo (help_string ? build_string (help_string) : Qnil, + Qnil, menu_object, make_number (item), 1); +} + + static Lisp_Object xmenu_show (f, x, y, for_click, keymaps, title, error) FRAME_PTR f; @@ -2450,13 +2659,17 @@ xmenu_show (f, x, y, for_click, keymaps, title, error) else { /* Create a new item within current pane. */ - Lisp_Object item_name, enable, descrip; + Lisp_Object item_name, enable, descrip, help; unsigned char *item_data; + char *help_string; 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]; + help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP]; + help_string = STRINGP (help) ? XSTRING (help)->data : NULL; + if (!NILP (descrip)) { int gap = maxwidth - STRING_BYTES (XSTRING (item_name)); @@ -2486,7 +2699,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error) if (XMenuAddSelection (FRAME_X_DISPLAY (f), menu, lpane, 0, item_data, - !NILP (enable)) + !NILP (enable), help_string) == XM_FAILURE) { XMenuDestroy (FRAME_X_DISPLAY (f), menu); @@ -2525,9 +2738,13 @@ xmenu_show (f, x, y, for_click, keymaps, title, error) XMenuSetAEQ (menu, TRUE); XMenuSetFreeze (menu, TRUE); pane = selidx = 0; - + + /* Help display under X won't work because XMenuActivate contains + a loop that doesn't give Emacs a chance to process it. */ + menu_help_frame = f; status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx, - x, y, ButtonReleaseMask, &datap); + x, y, ButtonReleaseMask, &datap, + menu_help_callback); #ifdef HAVE_X_WINDOWS @@ -2602,6 +2819,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error) #endif /* HAVE_MENUS */ +void syms_of_xmenu () { staticpro (&menu_items);