+
+#if defined(LWLIB_MENUBARS_LUCID)
+static void
+menu_move_up (void)
+{
+ widget_value *current = lw_get_entries (False);
+ widget_value *entries = lw_get_entries (True);
+ widget_value *prev = NULL;
+
+ while (entries != current)
+ {
+ if (entries->name /*&& entries->enabled*/) prev = entries;
+ entries = entries->next;
+ assert (entries);
+ }
+
+ if (!prev)
+ /* move to last item */
+ {
+ while (entries->next)
+ {
+ if (entries->name /*&& entries->enabled*/) prev = entries;
+ entries = entries->next;
+ }
+ if (prev)
+ {
+ if (entries->name /*&& entries->enabled*/)
+ prev = entries;
+ }
+ else
+ {
+ /* no selectable items in this menu, pop up to previous level */
+ lw_pop_menu ();
+ return;
+ }
+ }
+ lw_set_item (prev);
+}
+
+static void
+menu_move_down (void)
+{
+ widget_value *current = lw_get_entries (False);
+ widget_value *new = current;
+
+ while (new->next)
+ {
+ new = new->next;
+ if (new->name /*&& new->enabled*/) break;
+ }
+
+ if (new==current||!(new->name/*||new->enabled*/))
+ {
+ new = lw_get_entries (True);
+ while (new!=current)
+ {
+ if (new->name /*&& new->enabled*/) break;
+ new = new->next;
+ }
+ if (new==current&&!(new->name /*|| new->enabled*/))
+ {
+ lw_pop_menu ();
+ return;
+ }
+ }
+
+ lw_set_item (new);
+}
+
+static void
+menu_move_left (void)
+{
+ int level = lw_menu_level ();
+ int l = level;
+ widget_value *current;
+
+ while (level-- >= 3)
+ lw_pop_menu ();
+
+ menu_move_up ();
+ current = lw_get_entries (False);
+ if (l > 2 && current->contents)
+ lw_push_menu (current->contents);
+}
+
+static void
+menu_move_right (void)
+{
+ int level = lw_menu_level ();
+ int l = level;
+ widget_value *current;
+
+ while (level-- >= 3)
+ lw_pop_menu ();
+
+ menu_move_down ();
+ current = lw_get_entries (False);
+ if (l > 2 && current->contents)
+ lw_push_menu (current->contents);
+}
+
+static void
+menu_select_item (widget_value *val)
+{
+ if (val == NULL)
+ val = lw_get_entries (False);
+
+ /* is match a submenu? */
+
+ if (val->contents)
+ {
+ /* enter the submenu */
+
+ lw_set_item (val);
+ lw_push_menu (val->contents);
+ }
+ else
+ {
+ /* Execute the menu entry by calling the menu's `select'
+ callback function
+ */
+ lw_kill_menus (val);
+ }
+}
+
+Lisp_Object
+command_builder_operate_menu_accelerator (struct command_builder *builder)
+{
+ /* this function can GC */
+
+ struct console *con = XCONSOLE (Vselected_console);
+ Lisp_Object evee = builder->most_current_event;
+ Lisp_Object binding;
+ widget_value *entries;
+
+ extern int lw_menu_accelerate; /* lwlib.c */
+
+#if 0
+ {
+ int i;
+ Lisp_Object t;
+ char buf[50];
+
+ t = builder->current_events;
+ i = 0;
+ while (!NILP (t))
+ {
+ i++;
+ sprintf (buf,"OPERATE (%d): ",i);
+ write_c_string (buf, Qexternal_debugging_output);
+ print_internal (t, Qexternal_debugging_output, 1);
+ write_c_string ("\n", Qexternal_debugging_output);
+ t = XEVENT_NEXT (t);
+ }
+ }
+#endif /* 0 */
+
+ /* menu accelerator keys don't go into keyboard macros */
+ if (!NILP (con->defining_kbd_macro) && NILP (Vexecuting_macro))
+ con->kbd_macro_ptr = con->kbd_macro_end;
+
+ /* don't echo menu accelerator keys */
+ /*reset_key_echo (builder, 1);*/
+
+ if (!lw_menu_accelerate)
+ {
+ /* `convert' mouse display to keyboard display
+ by entering the open submenu
+ */
+ entries = lw_get_entries (False);
+ if (entries->contents)
+ {
+ lw_push_menu (entries->contents);
+ lw_display_menu (CurrentTime);
+ }
+ }
+
+ /* compare event to the current menu accelerators */
+
+ entries=lw_get_entries (True);
+
+ while (entries)
+ {
+ Lisp_Object accel;
+ VOID_TO_LISP (accel, entries->accel);
+ if (entries->name && !NILP (accel))
+ {
+ if (event_matches_key_specifier_p (XEVENT (evee), accel))
+ {
+ /* a match! */
+
+ menu_select_item (entries);
+
+ if (lw_menu_active) lw_display_menu (CurrentTime);
+
+ reset_this_command_keys (Vselected_console, 1);
+ /*reset_command_builder_event_chain (builder);*/
+ return Vmenu_accelerator_map;
+ }
+ }
+ entries = entries->next;
+ }
+
+ /* try to look up event in menu-accelerator-map */
+
+ binding = event_binding_in (evee, Vmenu_accelerator_map, 1);
+
+ if (NILP (binding))
+ {
+ /* beep at user for undefined key */
+ return Qnil;
+ }
+ else
+ {
+ if (EQ (binding, Qmenu_quit))
+ {
+ /* turn off menus and set quit flag */
+ lw_kill_menus (NULL);
+ Vquit_flag = Qt;
+ }
+ else if (EQ (binding, Qmenu_up))
+ {
+ int level = lw_menu_level ();
+ if (level > 2)
+ menu_move_up ();
+ }
+ else if (EQ (binding, Qmenu_down))
+ {
+ int level = lw_menu_level ();
+ if (level > 2)
+ menu_move_down ();
+ else
+ menu_select_item (NULL);
+ }
+ else if (EQ (binding, Qmenu_left))
+ {
+ int level = lw_menu_level ();
+ if (level > 3)
+ {
+ lw_pop_menu ();
+ lw_display_menu (CurrentTime);
+ }
+ else
+ menu_move_left ();
+ }
+ else if (EQ (binding, Qmenu_right))
+ {
+ int level = lw_menu_level ();
+ if (level > 2 &&
+ lw_get_entries (False)->contents)
+ {
+ widget_value *current = lw_get_entries (False);
+ if (current->contents)
+ menu_select_item (NULL);
+ }
+ else
+ menu_move_right ();
+ }
+ else if (EQ (binding, Qmenu_select))
+ menu_select_item (NULL);
+ else if (EQ (binding, Qmenu_escape))
+ {
+ int level = lw_menu_level ();
+
+ if (level > 2)
+ {
+ lw_pop_menu ();
+ lw_display_menu (CurrentTime);
+ }
+ else
+ {
+ /* turn off menus quietly */
+ lw_kill_menus (NULL);
+ }
+ }
+ else if (KEYMAPP (binding))
+ {
+ /* prefix key */
+ reset_this_command_keys (Vselected_console, 1);
+ /*reset_command_builder_event_chain (builder);*/
+ return binding;
+ }
+ else
+ {
+ /* turn off menus and execute binding */
+ lw_kill_menus (NULL);
+ reset_this_command_keys (Vselected_console, 1);
+ /*reset_command_builder_event_chain (builder);*/
+ return binding;
+ }
+ }
+
+ if (lw_menu_active) lw_display_menu (CurrentTime);
+
+ reset_this_command_keys (Vselected_console, 1);
+ /*reset_command_builder_event_chain (builder);*/
+
+ return Vmenu_accelerator_map;
+}
+
+static Lisp_Object
+menu_accelerator_junk_on_error (Lisp_Object errordata, Lisp_Object ignored)
+{
+ Vmenu_accelerator_prefix = Qnil;
+ Vmenu_accelerator_modifiers = Qnil;
+ Vmenu_accelerator_enabled = Qnil;
+ if (!NILP (errordata))
+ {
+ Lisp_Object args[2];
+
+ args[0] = build_string ("Error in menu accelerators (setting to nil)");
+ /* #### This should call
+ (with-output-to-string (display-error errordata))
+ but that stuff is all in Lisp currently. */
+ args[1] = errordata;
+ warn_when_safe_lispobj
+ (Qerror, Qwarning,
+ emacs_doprnt_string_lisp ((const Bufbyte *) "%s: %s",
+ Qnil, -1, 2, args));
+ }
+
+ return Qnil;
+}
+
+static Lisp_Object
+menu_accelerator_safe_compare (Lisp_Object event0)
+{
+ if (CONSP (Vmenu_accelerator_prefix))
+ {
+ Lisp_Object t;
+ t=Vmenu_accelerator_prefix;
+ while (!NILP (t)
+ && !NILP (event0)
+ && event_matches_key_specifier_p (XEVENT (event0), Fcar (t)))
+ {
+ t = Fcdr (t);
+ event0 = XEVENT_NEXT (event0);
+ }
+ if (!NILP (t))
+ return Qnil;
+ }
+ else if (NILP (event0))
+ return Qnil;
+ else if (event_matches_key_specifier_p (XEVENT (event0), Vmenu_accelerator_prefix))
+ event0 = XEVENT_NEXT (event0);
+ else
+ return Qnil;
+ return event0;
+}
+
+static Lisp_Object
+menu_accelerator_safe_mod_compare (Lisp_Object cons)
+{
+ return (event_matches_key_specifier_p (XEVENT (XCAR (cons)), XCDR (cons))
+ ? Qt
+ : Qnil);
+}
+
+Lisp_Object
+command_builder_find_menu_accelerator (struct command_builder *builder)
+{
+ /* this function can GC */
+ Lisp_Object event0 = builder->current_events;
+ struct console *con = XCONSOLE (Vselected_console);
+ struct frame *f = XFRAME (CONSOLE_SELECTED_FRAME (con));
+ Widget menubar_widget;
+
+ /* compare entries in event0 against the menu prefix */
+
+ if ((!CONSOLE_X_P (XCONSOLE (builder->console))) || NILP (event0) ||
+ XEVENT (event0)->event_type != key_press_event)
+ return Qnil;
+
+ if (!NILP (Vmenu_accelerator_prefix))
+ {
+ event0 = condition_case_1 (Qerror,
+ menu_accelerator_safe_compare,
+ event0,
+ menu_accelerator_junk_on_error,
+ Qnil);
+ }
+
+ if (NILP (event0))
+ return Qnil;
+
+ menubar_widget = FRAME_X_MENUBAR_WIDGET (f);
+ if (menubar_widget
+ && CONSP (Vmenu_accelerator_modifiers))
+ {
+ Lisp_Object fake = Qnil;
+ Lisp_Object last = Qnil;
+ struct gcpro gcpro1;
+ Lisp_Object matchp;
+
+ widget_value *val;
+ LWLIB_ID id = XPOPUP_DATA (f->menubar_data)->id;
+
+ val = lw_get_all_values (id);
+ if (val)
+ {
+ val = val->contents;
+
+ fake = Fcopy_sequence (Vmenu_accelerator_modifiers);
+ last = fake;
+
+ while (!NILP (Fcdr (last)))
+ last = Fcdr (last);
+
+ Fsetcdr (last, Fcons (Qnil, Qnil));
+ last = Fcdr (last);
+ }
+
+ fake = Fcons (Qnil, fake);
+
+ GCPRO1 (fake);
+
+ while (val)
+ {
+ Lisp_Object accel;
+ VOID_TO_LISP (accel, val->accel);
+ if (val->name && !NILP (accel))
+ {
+ Fsetcar (last, accel);
+ Fsetcar (fake, event0);
+ matchp = condition_case_1 (Qerror,
+ menu_accelerator_safe_mod_compare,
+ fake,
+ menu_accelerator_junk_on_error,
+ Qnil);
+ if (!NILP (matchp))
+ {
+ /* we found one! */
+
+ lw_set_menu (menubar_widget, val);
+ /* yah - yet another hack.
+ pretend emacs timestamp is the same as an X timestamp,
+ which for the moment it is. (read events.h)
+ */
+ lw_map_menu (XEVENT (event0)->timestamp);
+
+ if (val->contents)
+ lw_push_menu (val->contents);
+
+ lw_display_menu (CurrentTime);
+
+ /* menu accelerator keys don't go into keyboard macros */
+ if (!NILP (con->defining_kbd_macro)
+ && NILP (Vexecuting_macro))
+ con->kbd_macro_ptr = con->kbd_macro_end;
+
+ /* don't echo menu accelerator keys */
+ /*reset_key_echo (builder, 1);*/
+ reset_this_command_keys (Vselected_console, 1);
+ UNGCPRO;
+
+ return Vmenu_accelerator_map;
+ }
+ }
+
+ val = val->next;
+ }
+
+ UNGCPRO;
+ }
+ return Qnil;
+}
+
+int
+x_kludge_lw_menu_active (void)
+{
+ return lw_menu_active;
+}
+
+DEFUN ("accelerate-menu", Faccelerate_menu, 0, 0, "_", /*
+Make the menubar active. Menu items can be selected using menu accelerators
+or by actions defined in menu-accelerator-map.
+*/
+ ())
+{
+ struct console *con = XCONSOLE (Vselected_console);
+ struct frame *f = XFRAME (CONSOLE_SELECTED_FRAME (con));
+ LWLIB_ID id;
+ widget_value *val;
+
+ if (NILP (f->menubar_data))
+ error ("Frame has no menubar.");
+
+ id = XPOPUP_DATA (f->menubar_data)->id;
+ val = lw_get_all_values (id);
+ val = val->contents;
+ lw_set_menu (FRAME_X_MENUBAR_WIDGET (f), val);
+ lw_map_menu (CurrentTime);
+
+ lw_display_menu (CurrentTime);
+
+ /* menu accelerator keys don't go into keyboard macros */
+ if (!NILP (con->defining_kbd_macro) && NILP (Vexecuting_macro))
+ con->kbd_macro_ptr = con->kbd_macro_end;
+
+ return Qnil;
+}
+#endif /* LWLIB_MENUBARS_LUCID */
+
+\f