Mercurial > hg > xemacs-beta
diff src/event-stream.c @ 412:697ef44129c6 r21-2-14
Import from CVS: tag r21-2-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:20:41 +0200 |
parents | de805c49cfc1 |
children | 41dbb7a9d5f2 |
line wrap: on
line diff
--- a/src/event-stream.c Mon Aug 13 11:19:22 2007 +0200 +++ b/src/event-stream.c Mon Aug 13 11:20:41 2007 +0200 @@ -23,20 +23,6 @@ /* Synched up with: Not in FSF. */ -/* Authorship: - - Created 1991 by Jamie Zawinski. - A great deal of work over the ages by Ben Wing (Mule-ization for 19.12, - device abstraction for 19.12/19.13, async timers for 19.14, - rewriting of focus code for 19.12, pre-idle hook for 19.12, - redoing of signal and quit handling for 19.9 and 19.12, - misc-user events to clean up menu/scrollbar handling for 19.11, - function-key-map/key-translation-map/keyboard-translate-table for - 19.13/19.14, open-dribble-file for 19.13, much other cleanup). - focus-follows-mouse from Chuck Thompson, 1995. - XIM stuff by Martin Buchholz, c. 1996?. -*/ - /* This file has been Mule-ized. */ /* @@ -52,6 +38,8 @@ /* TODO: This stuff is way too hard to maintain - needs rework. + (global-set-key "\C-p" global-map) causes a crash - need recursion check. + C-x @ h <scrollbar-drag> x causes a crash. The command builder should deal only with key and button events. @@ -74,6 +62,14 @@ #include <config.h> #include "lisp.h" +#ifdef HAVE_X_WINDOWS +#include "console-x.h" /* for menu accelerators ... */ +#include "gui-x.h" +#include "../lwlib/lwlib.h" +#else +#define lw_menu_active 0 +#endif + #include "blocktype.h" #include "buffer.h" #include "commands.h" @@ -85,7 +81,7 @@ #include "keymap.h" #include "lstream.h" #include "macros.h" /* for defining_keyboard_macro */ -#include "menubar.h" /* #### for evil kludges. */ +#include "opaque.h" #include "process.h" #include "window.h" @@ -106,30 +102,29 @@ Lisp_Object Qundefined_keystroke_sequence; +Lisp_Object Qcommand_execute; + Lisp_Object Qcommand_event_p; /* Hooks to run before and after each command. */ Lisp_Object Vpre_command_hook, Vpost_command_hook; Lisp_Object Qpre_command_hook, Qpost_command_hook; -/* See simple.el */ -Lisp_Object Qhandle_pre_motion_command, Qhandle_post_motion_command; - /* Hook run when XEmacs is about to be idle. */ Lisp_Object Qpre_idle_hook, Vpre_idle_hook; /* Control gratuitous keyboard focus throwing. */ int focus_follows_mouse; -int modifier_keys_are_sticky; - -#if 0 /* FSF Emacs crap */ +#ifdef ILL_CONCEIVED_HOOK /* Hook run after a command if there's no more input soon. */ Lisp_Object Qpost_command_idle_hook, Vpost_command_idle_hook; /* Delay time in microseconds before running post-command-idle-hook. */ int post_command_idle_delay; - +#endif /* ILL_CONCEIVED_HOOK */ + +#ifdef DEFERRED_ACTION_CRAP /* List of deferred actions to be performed at a later time. The precise format isn't relevant here; we just check whether it is nil. */ Lisp_Object Vdeferred_action_list; @@ -137,7 +132,7 @@ /* Function to call to handle deferred actions, when there are any. */ Lisp_Object Vdeferred_action_function; Lisp_Object Qdeferred_action_function; -#endif /* FSF Emacs crap */ +#endif /* DEFERRED_ACTION_CRAP */ /* Non-nil disable property on a command means do not execute it; call disabled-command-hook's value instead. */ @@ -172,20 +167,13 @@ static Lisp_Object Qunread_command_events, Qunread_command_event; /* Previous command, represented by a Lisp object. - Does not include prefix commands and arg setting commands. */ + Does not include prefix commands and arg setting commands */ Lisp_Object Vlast_command; -/* Contents of this-command-properties for the last command. */ -Lisp_Object Vlast_command_properties; - /* If a command sets this, the value goes into - last-command for the next command. */ + previous-command for the next command. */ Lisp_Object Vthis_command; -/* If a command sets this, the value goes into - last-command-properties for the next command. */ -Lisp_Object Vthis_command_properties; - /* The value of point when the last command was executed. */ Bufpos last_point_position; @@ -250,7 +238,29 @@ recent-keys. */ int inhibit_input_event_recording; -Lisp_Object Qself_insert_defer_undo; +/* prefix key(s) that must match in order to activate menu. + This is ugly. fix me. + */ +Lisp_Object Vmenu_accelerator_prefix; + +/* list of modifier keys to match accelerator for top level menus */ +Lisp_Object Vmenu_accelerator_modifiers; + +/* whether menu accelerators are enabled */ +Lisp_Object Vmenu_accelerator_enabled; + +/* keymap for auxiliary menu accelerator functions */ +Lisp_Object Vmenu_accelerator_map; + +Lisp_Object Qmenu_force; +Lisp_Object Qmenu_fallback; +Lisp_Object Qmenu_quit; +Lisp_Object Qmenu_up; +Lisp_Object Qmenu_down; +Lisp_Object Qmenu_left; +Lisp_Object Qmenu_right; +Lisp_Object Qmenu_select; +Lisp_Object Qmenu_escape; /* this is in keymap.c */ extern Lisp_Object Fmake_keymap (Lisp_Object name); @@ -279,6 +289,60 @@ /* The callback routines for the window system or terminal driver */ struct event_stream *event_stream; +/* This structure is what we use to encapsulate the state of a command sequence + being composed; key events are executed by adding themselves to the command + builder; if the command builder is then complete (does not still represent + a prefix key sequence) it executes the corresponding command. + */ +struct command_builder +{ + struct lcrecord_header header; + Lisp_Object console; /* back pointer to the console this command + builder is for */ + /* Qnil, or a Lisp_Event representing the first event read + * after the last command completed. Threaded. */ + /* #### NYI */ + Lisp_Object prefix_events; + /* Qnil, or a Lisp_Event representing event in the current + * keymap-lookup sequence. Subsequent events are threaded via + * the event's next slot */ + Lisp_Object current_events; + /* Last elt of above */ + Lisp_Object most_current_event; + /* Last elt before function map code took over. What this means is: + All prefixes up to (but not including) this event have non-nil + bindings, but the prefix including this event has a nil binding. + Any events in the chain after this one were read solely because + we're part of a possible function key. If we end up with + something that's not part of a possible function key, we have to + unread all of those events. */ + Lisp_Object last_non_munged_event; + /* One set of values for function-key-map, one for key-translation-map */ + struct munging_key_translation + { + /* First event that can begin a possible function key sequence + (to be translated according to function-key-map). Normally + this is the first event in the chain. However, once we've + translated a sequence through function-key-map, this will point + to the first event after the translated sequence: we don't ever + want to translate any events twice through function-key-map, or + things could get really screwed up (e.g. if the user created a + translation loop). If this is nil, then the next-read event is + the first that can begin a function key sequence. */ + Lisp_Object first_mungeable_event; + } munge_me[2]; + + Bufbyte *echo_buf; + Bytecount echo_buf_length; /* size of echo_buf */ + Bytecount echo_buf_index; /* index into echo_buf + * -1 before doing echoing for new cmd */ + /* Self-insert-command is magic in that it doesn't always push an undo- + boundary: up to 20 consecutive self-inserts can happen before an undo- + boundary is pushed. This variable is that counter. + */ + int self_insert_countdown; +}; + static void echo_key_event (struct command_builder *, Lisp_Object event); static void maybe_kbd_translate (Lisp_Object event); @@ -321,18 +385,19 @@ XRECORD (x, command_builder, struct command_builder) #define XSETCOMMAND_BUILDER(x, p) XSETRECORD (x, p, command_builder) #define COMMAND_BUILDERP(x) RECORDP (x, command_builder) +#define GC_COMMAND_BUILDERP(x) GC_RECORDP (x, command_builder) #define CHECK_COMMAND_BUILDER(x) CHECK_RECORD (x, command_builder) static Lisp_Object -mark_command_builder (Lisp_Object obj) +mark_command_builder (Lisp_Object obj, void (*markobj) (Lisp_Object)) { struct command_builder *builder = XCOMMAND_BUILDER (obj); - mark_object (builder->prefix_events); - mark_object (builder->current_events); - mark_object (builder->most_current_event); - mark_object (builder->last_non_munged_event); - mark_object (builder->munge_me[0].first_mungeable_event); - mark_object (builder->munge_me[1].first_mungeable_event); + markobj (builder->prefix_events); + markobj (builder->current_events); + markobj (builder->most_current_event); + markobj (builder->last_non_munged_event); + markobj (builder->munge_me[0].first_mungeable_event); + markobj (builder->munge_me[1].first_mungeable_event); return builder->console; } @@ -348,7 +413,7 @@ DEFINE_LRECORD_IMPLEMENTATION ("command-builder", command_builder, mark_command_builder, internal_object_printer, - finalize_command_builder, 0, 0, 0, + finalize_command_builder, 0, 0, struct command_builder); static void @@ -444,15 +509,8 @@ return event_stream && event_stream->event_pending_p (user); } -static void -event_stream_force_event_pending (struct frame* f) -{ - if (event_stream->force_event_pending) - event_stream->force_event_pending (f); -} - static int -maybe_read_quit_event (Lisp_Event *event) +maybe_read_quit_event (struct Lisp_Event *event) { /* A C-g that came from `sigint_happened' will always come from the controlling terminal. If that doesn't exist, however, then the @@ -479,7 +537,7 @@ } void -event_stream_next_event (Lisp_Event *event) +event_stream_next_event (struct Lisp_Event *event) { Lisp_Object event_obj; @@ -523,7 +581,7 @@ } void -event_stream_handle_magic_event (Lisp_Event *event) +event_stream_handle_magic_event (struct Lisp_Event *event) { check_event_stream_ok (EVENT_STREAM_READ); event_stream->handle_magic_event_cb (event); @@ -566,7 +624,7 @@ } void -event_stream_select_process (Lisp_Process *proc) +event_stream_select_process (struct Lisp_Process *proc) { check_event_stream_ok (EVENT_STREAM_PROCESS); if (!get_process_selected_p (proc)) @@ -577,7 +635,7 @@ } void -event_stream_unselect_process (Lisp_Process *proc) +event_stream_unselect_process (struct Lisp_Process *proc) { check_event_stream_ok (EVENT_STREAM_PROCESS); if (get_process_selected_p (proc)) @@ -678,10 +736,7 @@ if (minibuf_level == 0 && echo_keystrokes > 0.0 -#if defined (HAVE_X_WINDOWS) && defined (LWLIB_MENUBARS_LUCID) - && !x_kludge_lw_menu_active () -#endif - ) + && !lw_menu_active) { if (!no_snooze) { @@ -744,7 +799,7 @@ } else if (CHARP (traduit)) { - Lisp_Event ev2; + struct Lisp_Event ev2; /* This used to call Fcharacter_to_event() directly into EVENT, but that can eradicate timestamps and other such stuff. @@ -930,7 +985,7 @@ used to indicate an absence of a timer. */ static int low_level_timeout_id_tick; -static struct low_level_timeout_blocktype +struct low_level_timeout_blocktype { Blocktype_declare (struct low_level_timeout); } *the_low_level_timeout_blocktype; @@ -1046,40 +1101,38 @@ static int timeout_id_tick; +/* Since timeout structures contain Lisp_Objects, they need to be GC'd + properly. The opaque data type provides a convenient way of doing + this without having to create a new Lisp object, since we can + provide our own mark function. */ + +struct timeout +{ + int id; /* Id we use to identify the timeout over its lifetime */ + int interval_id; /* Id for this particular interval; this may + be different each time the timeout is + signalled.*/ + Lisp_Object function, object; /* Function and object associated + with timeout. */ + EMACS_TIME next_signal_time; /* Absolute time when the timeout + is next going to be signalled. */ + unsigned int resignal_msecs; /* How far after the next timeout + should the one after that + occur? */ +}; + static Lisp_Object pending_timeout_list, pending_async_timeout_list; static Lisp_Object Vtimeout_free_list; static Lisp_Object -mark_timeout (Lisp_Object obj) +mark_timeout (Lisp_Object obj, void (*markobj) (Lisp_Object)) { - Lisp_Timeout *tm = XTIMEOUT (obj); - mark_object (tm->function); + struct timeout *tm = (struct timeout *) XOPAQUE_DATA (obj); + markobj (tm->function); return tm->object; } -/* Should never, ever be called. (except by an external debugger) */ -static void -print_timeout (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag) -{ - const Lisp_Timeout *t = XTIMEOUT (obj); - char buf[64]; - - sprintf (buf, "#<INTERNAL OBJECT (XEmacs bug?) (timeout) 0x%lx>", - (unsigned long) t); - write_c_string (buf, printcharfun); -} - -static const struct lrecord_description timeout_description[] = { - { XD_LISP_OBJECT, offsetof (Lisp_Timeout, function) }, - { XD_LISP_OBJECT, offsetof (Lisp_Timeout, object) }, - { XD_END } -}; - -DEFINE_LRECORD_IMPLEMENTATION ("timeout", timeout, - mark_timeout, print_timeout, - 0, 0, 0, timeout_description, Lisp_Timeout); - /* Generate a timeout and return its ID. */ int @@ -1088,8 +1141,8 @@ Lisp_Object function, Lisp_Object object, int async_p) { - Lisp_Object op = allocate_managed_lcrecord (Vtimeout_free_list); - Lisp_Timeout *timeout = XTIMEOUT (op); + Lisp_Object op = allocate_managed_opaque (Vtimeout_free_list, 0); + struct timeout *timeout = (struct timeout *) XOPAQUE_DATA (op); EMACS_TIME current_time; EMACS_TIME interval; @@ -1138,7 +1191,7 @@ Lisp_Object *function, Lisp_Object *object) { Lisp_Object op = Qnil, rest; - Lisp_Timeout *timeout; + struct timeout *timeout; Lisp_Object *timeout_list; struct gcpro gcpro1; int id; @@ -1151,16 +1204,16 @@ /* Find the timeout on the list of pending ones. */ LIST_LOOP (rest, *timeout_list) { - timeout = XTIMEOUT (XCAR (rest)); + timeout = (struct timeout *) XOPAQUE_DATA (XCAR (rest)); if (timeout->interval_id == interval_id) break; } assert (!NILP (rest)); op = XCAR (rest); - timeout = XTIMEOUT (op); + timeout = (struct timeout *) XOPAQUE_DATA (op); /* We make sure to snarf the data out of the timeout object before - we free it with free_managed_lcrecord(). */ + we free it with free_managed_opaque(). */ id = timeout->id; *function = timeout->function; *object = timeout->object; @@ -1202,7 +1255,7 @@ *timeout_list = noseeum_cons (op, *timeout_list); } else - free_managed_lcrecord (Vtimeout_free_list, op); + free_managed_opaque (Vtimeout_free_list, op); UNGCPRO; return id; @@ -1211,7 +1264,7 @@ void event_stream_disable_wakeup (int id, int async_p) { - Lisp_Timeout *timeout = 0; + struct timeout *timeout = 0; Lisp_Object rest; Lisp_Object *timeout_list; @@ -1223,7 +1276,7 @@ /* Find the timeout on the list of pending ones, if it's still there. */ LIST_LOOP (rest, *timeout_list) { - timeout = XTIMEOUT (XCAR (rest)); + timeout = (struct timeout *) XOPAQUE_DATA (XCAR (rest)); if (timeout->id == id) break; } @@ -1239,14 +1292,14 @@ event_stream_remove_async_timeout (timeout->interval_id); else event_stream_remove_timeout (timeout->interval_id); - free_managed_lcrecord (Vtimeout_free_list, op); + free_managed_opaque (Vtimeout_free_list, op); } } static int event_stream_wakeup_pending_p (int id, int async_p) { - Lisp_Timeout *timeout; + struct timeout *timeout; Lisp_Object rest; Lisp_Object timeout_list; int found = 0; @@ -1260,7 +1313,7 @@ /* Find the element on the list of pending ones, if it's still there. */ LIST_LOOP (rest, timeout_list) { - timeout = XTIMEOUT (XCAR (rest)); + timeout = (struct timeout *) XOPAQUE_DATA (XCAR (rest)); if (timeout->id == id) { found = 1; @@ -1963,7 +2016,7 @@ } else { - Lisp_Event *e = XEVENT (target_event); + struct Lisp_Event *e = XEVENT (target_event); /* The command_event_queue was empty. Wait for an event. */ event_stream_next_event (e); @@ -2070,6 +2123,9 @@ XCOMMAND_BUILDER (con->command_builder); int store_this_key = 0; struct gcpro gcpro1; +#ifdef LWLIB_MENUBARS_LUCID + extern int in_menu_callback; /* defined in menubar-x.c */ +#endif /* LWLIB_MENUBARS_LUCID */ GCPRO1 (event); /* DO NOT do QUIT anywhere within this function or the functions it calls. @@ -2345,56 +2401,6 @@ return event; } -DEFUN ("dispatch-non-command-events", Fdispatch_non_command_events, 0, 0, 0, /* -Dispatch any pending "magic" events. - -This function is useful for forcing the redisplay of native -widgets. Normally these are redisplayed through a native window-system -event encoded as magic event, rather than by the redisplay code. This -function does not call redisplay or do any of the other things that -`next-event' does. -*/ - ()) -{ - /* This function can GC */ - Lisp_Object event = Qnil; - struct gcpro gcpro1; - GCPRO1 (event); - event = Fmake_event (Qnil, Qnil); - - /* Make sure that there will be something in the native event queue - so that externally managed things (e.g. widgets) get some CPU - time. */ - event_stream_force_event_pending (selected_frame ()); - - while (event_stream_event_pending_p (0)) - { - QUIT; /* next_event_internal() does not QUIT. */ - - /* We're a generator of the command_event_queue, so we can't be a - consumer as well. Also, we have no reason to consult the - command_event_queue; there are only user and eval-events there, - and we'd just have to put them back anyway. - */ - next_event_internal (event, 0); /* blocks */ - /* See the comment in accept-process-output about Vquit_flag */ - if (XEVENT_TYPE (event) == magic_event || - XEVENT_TYPE (event) == timeout_event || - XEVENT_TYPE (event) == process_event || - XEVENT_TYPE (event) == pointer_motion_event) - execute_internal_event (event); - else - { - enqueue_command_event_1 (event); - break; - } - } - - Fdeallocate_event (event); - UNGCPRO; - return Qnil; -} - static void reset_current_events (struct command_builder *command_builder) { @@ -3032,7 +3038,7 @@ case timeout_event: { - Lisp_Event *e = XEVENT (event); + struct Lisp_Event *e = XEVENT (event); if (!NILP (e->event.timeout.function)) call1 (e->event.timeout.function, e->event.timeout.object); @@ -3090,6 +3096,514 @@ return event_binding (event0, 1); } +#if defined(HAVE_X_WINDOWS) && defined(LWLIB_MENUBARS_LUCID) +static void +menu_move_up (void) +{ + widget_value *current, *prev; + widget_value *entries; + + current = lw_get_entries (False); + entries = lw_get_entries (True); + prev = NULL; + if (current != entries) + { + 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; + widget_value *new; + + current = lw_get_entries (False); + 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) + { + --level; + 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) + { + --level; + 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); + } +} + +static 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); +} + +static 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; + 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; +} + + +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 /* HAVE_X_WINDOWS && HAVE_MENUBARS */ + /* See if we can do function-key-map or key-translation-map translation on the current events in the command builder. If so, do this, and return the resulting binding, if any. */ @@ -3211,11 +3725,9 @@ return Qnil; } - /* if we're currently in a menu accelerator, check there for further - events */ - /* #### fuck me! who wrote this crap? think "abstraction", baby. */ + /* if we're currently in a menu accelerator, check there for further events */ #if defined(HAVE_X_WINDOWS) && defined(LWLIB_MENUBARS_LUCID) - if (x_kludge_lw_menu_active ()) + if (lw_menu_active) { return command_builder_operate_menu_accelerator (builder); } @@ -3266,14 +3778,14 @@ Lisp_Object terminal = builder->most_current_event; struct key_data* key = & XEVENT (terminal)->event.key; Emchar c = 0; - if ((key->modifiers & XEMACS_MOD_SHIFT) + if ((key->modifiers & MOD_SHIFT) || (CHAR_OR_CHAR_INTP (key->keysym) && ((c = XCHAR_OR_CHAR_INT (key->keysym)), c >= 'A' && c <= 'Z'))) { - Lisp_Event terminal_copy = *XEVENT (terminal); - - if (key->modifiers & XEMACS_MOD_SHIFT) - key->modifiers &= (~ XEMACS_MOD_SHIFT); + struct Lisp_Event terminal_copy = *XEVENT (terminal); + + if (key->modifiers & MOD_SHIFT) + key->modifiers &= (~ MOD_SHIFT); else key->keysym = make_char (c + 'a' - 'A'); @@ -3663,7 +4175,7 @@ if (EVENTP (recent) && event_matches_key_specifier_p (XEVENT (recent), Vmeta_prefix_char)) { - Lisp_Event *e; + struct Lisp_Event *e; /* When we see a sequence like "ESC x", pretend we really saw "M-x". DoubleThink the recent-keys and this-command-keys as well. */ @@ -3674,10 +4186,10 @@ Fcopy_event (event, recent); e = XEVENT (recent); if (e->event_type == key_press_event) - e->event.key.modifiers |= XEMACS_MOD_META; + e->event.key.modifiers |= MOD_META; else if (e->event_type == button_press_event || e->event_type == button_release_event) - e->event.button.modifiers |= XEMACS_MOD_META; + e->event.button.modifiers |= MOD_META; else abort (); @@ -3708,11 +4220,7 @@ if (KEYMAPP (leaf)) { -#if defined (HAVE_X_WINDOWS) && defined (LWLIB_MENUBARS_LUCID) - if (!x_kludge_lw_menu_active ()) -#else - if (1) -#endif + if (!lw_menu_active) { Lisp_Object prompt = Fkeymap_prompt (leaf, Qt); if (STRINGP (prompt)) @@ -3732,20 +4240,19 @@ else maybe_echo_keys (command_builder, 0); } - else if (!NILP (Vquit_flag)) - { - Lisp_Object quit_event = Fmake_event (Qnil, Qnil); - Lisp_Event *e = XEVENT (quit_event); - /* if quit happened during menu acceleration, pretend we read it */ - struct console *con = XCONSOLE (Fselected_console ()); - int ch = CONSOLE_QUIT_CHAR (con); - - character_to_event (ch, e, con, 1, 1); - e->channel = make_console (con); - - enqueue_command_event (quit_event); - Vquit_flag = Qnil; - } + else if (!NILP (Vquit_flag)) { + Lisp_Object quit_event = Fmake_event(Qnil, Qnil); + struct Lisp_Event *e = XEVENT (quit_event); + /* if quit happened during menu acceleration, pretend we read it */ + struct console *con = XCONSOLE (Fselected_console ()); + int ch = CONSOLE_QUIT_CHAR (con); + + character_to_event (ch, e, con, 1, 1); + e->channel = make_console (con); + + enqueue_command_event (quit_event); + Vquit_flag = Qnil; + } } else if (!NILP (leaf)) { @@ -3864,9 +4371,6 @@ { /* Start a new command next time */ Vlast_command = Vthis_command; - Vlast_command_properties = Vthis_command_properties; - Vthis_command_properties = Qnil; - /* Emacs 18 doesn't unconditionally clear the echoed keystrokes, so we don't either */ reset_this_command_keys (make_console (con), 0); @@ -3887,9 +4391,6 @@ safe_run_hook_trapping_errors ("Error in `pre-command-hook' (setting hook to nil)", Qpre_command_hook, 1); - - /* This is a kludge, but necessary; see simple.el */ - call0 (Qhandle_pre_motion_command); } /* Run the post command hook. */ @@ -3909,18 +4410,14 @@ Lisp_Object win = Fselected_window (Qnil); +#if 0 /* If the last command deleted the frame, `win' might be nil. It seems safest to do nothing in this case. */ - /* Note: Someone added the following comment and put #if 0's around - this code, not realizing that doing this invites a crash in the - line after. */ - /* #### This doesn't really fix the problem, + /* ### This doesn't really fix the problem, if delete-frame is called by some hook */ if (NILP (win)) return; - - /* This is a kludge, but necessary; see simple.el */ - call0 (Qhandle_post_motion_command); +#endif if (! zmacs_region_stays && (!MINI_WINDOW_P (XWINDOW (win)) @@ -3933,10 +4430,12 @@ ("Error in `post-command-hook' (setting hook to nil)", Qpost_command_hook, 1); -#if 0 /* FSF Emacs crap */ +#ifdef DEFERRED_ACTION_CRAP if (!NILP (Vdeferred_action_list)) call0 (Vdeferred_action_function); - +#endif + +#ifdef ILL_CONCEIVED_HOOK if (NILP (Vunread_command_events) && NILP (Vexecuting_macro) && !NILP (Vpost_command_idle_hook) @@ -3945,9 +4444,9 @@ safe_run_hook_trapping_errors ("Error in `post-command-idle-hook' (setting hook to nil)", Qpost_command_idle_hook, 1); -#endif /* FSF Emacs crap */ - -#if 0 /* FSF Emacs */ +#endif + +#if 0 /* FSFmacs */ if (!NILP (current_buffer->mark_active)) { if (!NILP (Vdeactivate_mark) && !NILP (Vtransient_mark_mode)) @@ -3959,7 +4458,7 @@ BUF_MODIFF (current_buffer) != prev_modiff) run_hook (intern ("activate-mark-hook")); } -#endif /* FSF Emacs */ +#endif /* FSFmacs */ /* #### Kludge!!! This is necessary to make sure that things are properly positioned even if post-command-hook moves point. @@ -3993,7 +4492,7 @@ { /* This function can GC */ struct command_builder *command_builder; - Lisp_Event *ev; + struct Lisp_Event *ev; Lisp_Object console; Lisp_Object channel; @@ -4107,35 +4606,15 @@ } else /* key sequence is bound to a command */ { - int magic_undo = 0; - int magic_undo_count = 20; - Vthis_command = leaf; - /* Don't push an undo boundary if the command set the prefix arg, or if we are executing a keyboard macro, or if in the minibuffer. If the command we are about to execute is self-insert, it's tricky: up to 20 consecutive self-inserts may be done without an undo boundary. This counter is reset as soon as a command other than self-insert-command is executed. - - Programmers can also use the `self-insert-defer-undo' - property to install that behavior on functions other - than `self-insert-command', or to change the magic - number 20 to something else. #### DOCUMENT THIS! */ - - if (SYMBOLP (leaf)) - { - Lisp_Object prop = Fget (leaf, Qself_insert_defer_undo, Qnil); - if (NATNUMP (prop)) - magic_undo = 1, magic_undo_count = XINT (prop); - else if (!NILP (prop)) - magic_undo = 1; - else if (EQ (leaf, Qself_insert_command)) - magic_undo = 1; - } - - if (!magic_undo) + */ + if (! EQ (leaf, Qself_insert_command)) command_builder->self_insert_countdown = 0; if (NILP (XCONSOLE (console)->prefix_arg) && NILP (Vexecuting_macro) @@ -4149,10 +4628,10 @@ && command_builder->self_insert_countdown == 0) Fundo_boundary (); - if (magic_undo) + if (EQ (leaf, Qself_insert_command)) { if (--command_builder->self_insert_countdown < 0) - command_builder->self_insert_countdown = magic_undo_count; + command_builder->self_insert_countdown = 20; } execute_command_event (command_builder, @@ -4338,7 +4817,7 @@ Calling this function directs the translated event to replace the original event, so that only one version of the event actually -appears in the echo area and in the value of `this-command-keys'. +appears in the echo area and in the value of `this-command-keys.'. */ ()) { @@ -4362,7 +4841,9 @@ { Emchar ch = XCHAR (keysym); Bufbyte str[MAX_EMCHAR_LEN]; - Bytecount len = set_charptr_emchar (str, ch); + Bytecount len; + + len = set_charptr_emchar (str, ch); Lstream_write (XLSTREAM (Vdribble_file), str, len); } else if (string_char_length (XSYMBOL (keysym)->name) == 1) @@ -4423,14 +4904,12 @@ void syms_of_event_stream (void) { - INIT_LRECORD_IMPLEMENTATION (command_builder); - INIT_LRECORD_IMPLEMENTATION (timeout); - defsymbol (&Qdisabled, "disabled"); defsymbol (&Qcommand_event_p, "command-event-p"); deferror (&Qundefined_keystroke_sequence, "undefined-keystroke-sequence", "Undefined keystroke sequence", Qerror); + defsymbol (&Qcommand_execute, "command-execute"); DEFSUBR (Frecent_keys); DEFSUBR (Frecent_keys_ring_size); @@ -4448,21 +4927,23 @@ DEFSUBR (Fadd_async_timeout); DEFSUBR (Fdisable_async_timeout); DEFSUBR (Fdispatch_event); - DEFSUBR (Fdispatch_non_command_events); DEFSUBR (Fread_key_sequence); DEFSUBR (Fthis_command_keys); DEFSUBR (Freset_this_command_lengths); DEFSUBR (Fopen_dribble_file); +#if defined(HAVE_X_WINDOWS) && defined(LWLIB_MENUBARS_LUCID) + DEFSUBR (Faccelerate_menu); +#endif defsymbol (&Qpre_command_hook, "pre-command-hook"); defsymbol (&Qpost_command_hook, "post-command-hook"); defsymbol (&Qunread_command_events, "unread-command-events"); defsymbol (&Qunread_command_event, "unread-command-event"); defsymbol (&Qpre_idle_hook, "pre-idle-hook"); - defsymbol (&Qhandle_pre_motion_command, "handle-pre-motion-command"); - defsymbol (&Qhandle_post_motion_command, "handle-post-motion-command"); -#if 0 /* FSF Emacs crap */ +#ifdef ILL_CONCEIVED_HOOK defsymbol (&Qpost_command_idle_hook, "post-command-idle-hook"); +#endif +#ifdef DEFERRED_ACTION_CRAP defsymbol (&Qdeferred_action_function, "deferred-action-function"); #endif defsymbol (&Qretry_undefined_key_binding_unshifted, @@ -4470,41 +4951,37 @@ defsymbol (&Qauto_show_make_point_visible, "auto-show-make-point-visible"); - defsymbol (&Qself_insert_defer_undo, "self-insert-defer-undo"); + defsymbol (&Qmenu_force, "menu-force"); + defsymbol (&Qmenu_fallback, "menu-fallback"); + + defsymbol (&Qmenu_quit, "menu-quit"); + defsymbol (&Qmenu_up, "menu-up"); + defsymbol (&Qmenu_down, "menu-down"); + defsymbol (&Qmenu_left, "menu-left"); + defsymbol (&Qmenu_right, "menu-right"); + defsymbol (&Qmenu_select, "menu-select"); + defsymbol (&Qmenu_escape, "menu-escape"); + defsymbol (&Qcancel_mode_internal, "cancel-mode-internal"); } void -reinit_vars_of_event_stream (void) -{ - recent_keys_ring_index = 0; - recent_keys_ring_size = 100; - num_input_chars = 0; - Vtimeout_free_list = make_lcrecord_list (sizeof (Lisp_Timeout), - &lrecord_timeout); - staticpro_nodump (&Vtimeout_free_list); - the_low_level_timeout_blocktype = - Blocktype_new (struct low_level_timeout_blocktype); - something_happened = 0; - recursive_sit_for = Qnil; -} - -void vars_of_event_stream (void) { - reinit_vars_of_event_stream (); + recent_keys_ring_index = 0; + recent_keys_ring_size = 100; Vrecent_keys_ring = Qnil; staticpro (&Vrecent_keys_ring); Vthis_command_keys = Qnil; staticpro (&Vthis_command_keys); Vthis_command_keys_tail = Qnil; - pdump_wire (&Vthis_command_keys_tail); + + num_input_chars = 0; command_event_queue = Qnil; staticpro (&command_event_queue); command_event_queue_tail = Qnil; - pdump_wire (&command_event_queue_tail); Vlast_selected_frame = Qnil; staticpro (&Vlast_selected_frame); @@ -4515,9 +4992,20 @@ pending_async_timeout_list = Qnil; staticpro (&pending_async_timeout_list); + Vtimeout_free_list = make_opaque_list (sizeof (struct timeout), + mark_timeout); + staticpro (&Vtimeout_free_list); + + the_low_level_timeout_blocktype = + Blocktype_new (struct low_level_timeout_blocktype); + + something_happened = 0; + last_point_position_buffer = Qnil; staticpro (&last_point_position_buffer); + recursive_sit_for = Qnil; + DEFVAR_LISP ("echo-keystrokes", &Vecho_keystrokes /* *Nonzero means echo unfinished commands after this many seconds of pause. */ ); @@ -4563,7 +5051,7 @@ */ ); focus_follows_mouse = 0; -#if 0 /* FSF Emacs crap */ +#ifdef ILL_CONCEIVED_HOOK /* Ill-conceived because it's not run in all sorts of cases where XEmacs is blocking. That's what `pre-idle-hook' is designed to solve. */ @@ -4580,7 +5068,9 @@ This is measured in microseconds. */ ); post_command_idle_delay = 5000; - +#endif /* ILL_CONCEIVED_HOOK */ + +#ifdef DEFERRED_ACTION_CRAP /* Random FSFmacs crap. There is absolutely nothing to gain, and a great deal to lose, in using this in place of just setting `post-command-hook'. */ @@ -4596,7 +5086,7 @@ whenever `deferred-action-list' is non-nil. */ ); Vdeferred_action_function = Qnil; -#endif /* FSF Emacs crap */ +#endif /* DEFERRED_ACTION_CRAP */ DEFVAR_LISP ("last-command-event", &Vlast_command_event /* Last keyboard or mouse button event that was part of a command. This @@ -4686,23 +5176,6 @@ */ ); Vthis_command = Qnil; - DEFVAR_LISP ("last-command-properties", &Vlast_command_properties /* -Value of `this-command-properties' for the last command. -Used by commands to help synchronize consecutive commands, in preference -to looking at `last-command' directly. -*/ ); - Vlast_command_properties = Qnil; - - DEFVAR_LISP ("this-command-properties", &Vthis_command_properties /* -Properties set by the current command. -At the beginning of each command, the current value of this variable is -copied to `last-command-properties', and then it is set to nil. Use `putf' -to add properties to this variable. Commands should use this to communicate -with pre/post-command hooks, subsequent commands, wrapping commands, etc. -in preference to looking at and/or setting `this-command'. -*/ ); - Vthis_command_properties = Qnil; - DEFVAR_LISP ("help-char", &Vhelp_char /* Character to recognize as meaning Help. When it is read, do `(eval help-form)', and display result if it's a string. @@ -4756,15 +5229,6 @@ */ ); Vretry_undefined_key_binding_unshifted = Qt; - DEFVAR_BOOL ("modifier-keys-are-sticky", &modifier_keys_are_sticky /* -*Non-nil makes modifier keys sticky. -This means that you can release the modifier key before pressing down -the key that you wish to be modified. Although this is non-standard -behavior, it is recommended because it reduces the strain on your hand, -thus reducing the incidence of the dreaded Emacs-pinky syndrome. -*/ ); - modifier_keys_are_sticky = 0; - #ifdef HAVE_XIM DEFVAR_LISP ("composed-character-default-binding", &Vcomposed_character_default_binding /* @@ -4825,6 +5289,41 @@ Non-nil inhibits recording of input-events to recent-keys ring. */ ); inhibit_input_event_recording = 0; + + DEFVAR_LISP("menu-accelerator-prefix", &Vmenu_accelerator_prefix /* +Prefix key(s) that must be typed before menu accelerators will be activated. +Set this to a value acceptable by define-key. +*/ ); + Vmenu_accelerator_prefix = Qnil; + + DEFVAR_LISP ("menu-accelerator-modifiers", &Vmenu_accelerator_modifiers /* +Modifier keys which must be pressed to get to the top level menu accelerators. +This is a list of modifier key symbols. All modifier keys must be held down +while a valid menu accelerator key is pressed in order for the top level +menu to become active. + +See also menu-accelerator-enabled and menu-accelerator-prefix. +*/ ); + Vmenu_accelerator_modifiers = list1 (Qmeta); + + DEFVAR_LISP ("menu-accelerator-enabled", &Vmenu_accelerator_enabled /* +Whether menu accelerator keys can cause the menubar to become active. +If 'menu-force or 'menu-fallback, then menu accelerator keys can +be used to activate the top level menu. Once the menubar becomes active, the +accelerator keys can be used regardless of the value of this variable. + +menu-force is used to indicate that the menu accelerator key takes +precedence over bindings in the current keymap(s). menu-fallback means +that bindings in the current keymap take precedence over menu accelerator keys. +Thus a top level menu with an accelerator of "T" would be activated on a +keypress of Meta-t if menu-accelerator-enabled is menu-force. +However, if menu-accelerator-enabled is menu-fallback, then +Meta-t will not activate the menubar and will instead run the function +transpose-words, to which it is normally bound. + +See also menu-accelerator-modifiers and menu-accelerator-prefix. +*/ ); + Vmenu_accelerator_enabled = Qnil; } void @@ -4832,6 +5331,41 @@ { Vkeyboard_translate_table = make_lisp_hash_table (100, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ); + + DEFVAR_LISP ("menu-accelerator-map", &Vmenu_accelerator_map /* +Keymap for use when the menubar is active. +The actions menu-quit, menu-up, menu-down, menu-left, menu-right, +menu-select and menu-escape can be mapped to keys in this map. + +menu-quit Immediately deactivate the menubar and any open submenus without + selecting an item. +menu-up Move the menu cursor up one row in the current menu. If the + move extends past the top of the menu, wrap around to the bottom. +menu-down Move the menu cursor down one row in the current menu. If the + move extends past the bottom of the menu, wrap around to the top. + If executed while the cursor is in the top level menu, move down + into the selected menu. +menu-left Move the cursor from a submenu into the parent menu. If executed + while the cursor is in the top level menu, move the cursor to the + left. If the move extends past the left edge of the menu, wrap + around to the right edge. +menu-right Move the cursor into a submenu. If the cursor is located in the + top level menu or is not currently on a submenu heading, then move + the cursor to the next top level menu entry. If the move extends + past the right edge of the menu, wrap around to the left edge. +menu-select Activate the item under the cursor. If the cursor is located on + a submenu heading, then move the cursor into the submenu. +menu-escape Pop up to the next level of menus. Moves from a submenu into its + parent menu. From the top level menu, this deactivates the + menubar. + +This keymap can also contain normal key-command bindings, in which case the +menubar is deactivated and the corresponding command is executed. + +The action bindings used by the menu accelerator code are designed to mimic +the actions of menu traversal keys in a commonly used PC operating system. +*/ ); + Vmenu_accelerator_map = Fmake_keymap(Qnil); } void