X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/e27b53f62f2bd216e85e1c83419fe41f7f8daab9..ffa85ae7a58613248810a0cb2978b5763794672d:/src/keyboard.c diff --git a/src/keyboard.c b/src/keyboard.c index c5a760b623..6c25c3d99e 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1,5 +1,6 @@ /* Keyboard and mouse input; editor command loop. - Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99 Free Software Foundation, Inc. + Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99, 2000 + Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -26,6 +27,7 @@ Boston, MA 02111-1307, USA. */ #include "lisp.h" #include "termhooks.h" #include "macros.h" +#include "keyboard.h" #include "frame.h" #include "window.h" #include "commands.h" @@ -33,11 +35,12 @@ Boston, MA 02111-1307, USA. */ #include "charset.h" #include "disptab.h" #include "dispextern.h" -#include "keyboard.h" #include "syntax.h" #include "intervals.h" #include "blockinput.h" #include "puresize.h" +#include "systime.h" +#include "atimer.h" #include #include @@ -70,7 +73,9 @@ Boston, MA 02111-1307, USA. */ /* Include systime.h after xterm.h to avoid double inclusion of time.h. */ #include "systime.h" +#ifndef USE_CRT_DLL extern int errno; +#endif /* Variables for blockinput.h: */ @@ -200,13 +205,18 @@ static int echoing; static struct kboard *ok_to_echo_at_next_pause; -/* The kboard currently echoing, or null for none. Set in echo_now to - the kboard echoing. Reset to 0 in cancel_echoing. If non-null, - and a current echo area message exists, we know that it comes from - echoing. */ +/* The kboard last echoing, or null for none. Reset to 0 in + cancel_echoing. If non-null, and a current echo area message + exists, and echo_message_buffer is eq to the current message + buffer, we know that the message comes from echo_kboard. */ static struct kboard *echo_kboard; +/* The buffer used for echoing. Set in echo_now, reset in + cancel_echoing. */ + +static Lisp_Object echo_message_buffer; + /* Nonzero means disregard local maps for the menu bar. */ static int inhibit_local_menu_bar_menus; @@ -376,6 +386,9 @@ Lisp_Object Qtimer_event_handler; key sequence that it reads. */ Lisp_Object read_key_sequence_cmd; +/* Echo unfinished commands after this many seconds of pause. */ +Lisp_Object Vecho_keystrokes; + /* Form to evaluate (if non-nil) when Emacs is started. */ Lisp_Object Vtop_level; @@ -442,9 +455,10 @@ int meta_key; extern char *pending_malloc_warning; /* Circular buffer for pre-read keyboard input. */ + static struct input_event kbd_buffer[KBD_BUFFER_SIZE]; -/* Vector to GCPRO the frames and windows mentioned in kbd_buffer. +/* Vector to GCPRO the Lisp objects referenced from kbd_buffer. The interrupt-level event handlers will never enqueue an event on a frame which is not in Vframe_list, and once an event is dequeued, @@ -463,14 +477,16 @@ static struct input_event kbd_buffer[KBD_BUFFER_SIZE]; Similar things happen when an event on a scroll bar is enqueued; the window may be deleted while the event is in the queue. - So, we use this vector to protect the frame_or_window field in the - event queue. That way, they'll be dequeued as dead frames or - windows, but still valid lisp objects. + So, we use this vector to protect the Lisp_Objects in the event + queue. That way, they'll be dequeued as dead frames or windows, + but still valid Lisp objects. If kbd_buffer[i].kind != no_event, then - (XVECTOR (kbd_buffer_frame_or_window)->contents[i] - == kbd_buffer[i].frame_or_window. */ -static Lisp_Object kbd_buffer_frame_or_window; + + AREF (kbd_buffer_gcpro, 2 * i) == kbd_buffer[i].frame_or_window. + AREF (kbd_buffer_gcpro, 2 * i + 1) == kbd_buffer[i].arg. */ + +static Lisp_Object kbd_buffer_gcpro; /* Pointer to next available character in kbd_buffer. If kbd_fetch_ptr == kbd_store_ptr, the buffer is empty. @@ -609,9 +625,11 @@ int flow_control; point to the boundary of the region. But, if a command sets this valiable to non-nil, we suppress this point adjustment. This variable is set to nil before reading a command. */ + Lisp_Object Vdisable_point_adjustment; /* If non-nil, always disable point adjustment. */ + Lisp_Object Vglobal_disable_point_adjustment; @@ -620,24 +638,32 @@ Lisp_Object Vglobal_disable_point_adjustment; /* Function for init_keyboard to call with no args (if nonzero). */ void (*keyboard_init_hook) (); -static int read_avail_input (); -static void get_input_pending (); -static int readable_events (); +static int read_avail_input P_ ((int)); +static void get_input_pending P_ ((int *, int)); +static int readable_events P_ ((int)); +static Lisp_Object read_char_x_menu_prompt P_ ((int, Lisp_Object *, + Lisp_Object, int *)); static Lisp_Object read_char_x_menu_prompt (); -static Lisp_Object read_char_minibuf_menu_prompt (); -static Lisp_Object make_lispy_event (); +static Lisp_Object read_char_minibuf_menu_prompt P_ ((int, int, + Lisp_Object *)); +static Lisp_Object make_lispy_event P_ ((struct input_event *)); #ifdef HAVE_MOUSE -static Lisp_Object make_lispy_movement (); +static Lisp_Object make_lispy_movement P_ ((struct frame *, Lisp_Object, + enum scroll_bar_part, + Lisp_Object, Lisp_Object, + unsigned long)); #endif -static Lisp_Object modify_event_symbol (); -static Lisp_Object make_lispy_switch_frame (); +static Lisp_Object modify_event_symbol P_ ((int, unsigned, Lisp_Object, + Lisp_Object, char **, + Lisp_Object *, unsigned)); +static Lisp_Object make_lispy_switch_frame P_ ((Lisp_Object)); +static int parse_solitary_modifier P_ ((Lisp_Object)); static int parse_solitary_modifier (); +static void save_getcjmp P_ ((jmp_buf)); static void save_getcjmp (); -static void restore_getcjmp (); +static void restore_getcjmp P_ ((jmp_buf)); static Lisp_Object apply_modifiers P_ ((int, Lisp_Object)); - -/* > 0 if we are to echo keystrokes. */ -static int echo_keystrokes; +static void clear_event P_ ((struct input_event *)); /* Nonzero means don't try to suspend even if the operating system seems to support it. */ @@ -767,11 +793,14 @@ echo_now () } echoing = 1; - echo_kboard = current_kboard; message2_nolog (current_kboard->echobuf, strlen (current_kboard->echobuf), ! NILP (current_buffer->enable_multibyte_characters)); echoing = 0; + /* Record in what buffer we echoed, and from which kboard. */ + echo_message_buffer = echo_area_buffer[0]; + echo_kboard = current_kboard; + if (waiting_for_input && !NILP (Vquit_flag)) quit_throw_to_read_char (); } @@ -784,8 +813,9 @@ cancel_echoing () current_kboard->immediate_echo = 0; current_kboard->echoptr = current_kboard->echobuf; current_kboard->echo_after_prompt = -1; - ok_to_echo_at_next_pause = 0; - echo_kboard = 0; + ok_to_echo_at_next_pause = NULL; + echo_kboard = NULL; + echo_message_buffer = Qnil; } /* Return the length of the current echo string. */ @@ -855,6 +885,14 @@ recursive_edit_1 () specbind (Qstandard_input, Qt); } +#ifdef HAVE_X_WINDOWS + /* The command loop has started a busy-cursor timer, so we have to + cancel it here, otherwise it will fire because the recursive edit + can take some time. */ + if (display_busy_cursor_p) + cancel_busy_cursor (); +#endif + val = command_loop (); if (EQ (val, Qt)) Fsignal (Qquit, Qnil); @@ -1164,6 +1202,10 @@ DEFUN ("top-level", Ftop_level, Stop_level, 0, 0, "", "Exit all recursive editing levels.") () { +#ifdef HAVE_X_WINDOWS + if (display_busy_cursor_p) + cancel_busy_cursor (); +#endif Fthrow (Qtop_level, Qnil); } @@ -1516,18 +1558,18 @@ command_loop_1 () #ifdef HAVE_X_WINDOWS if (display_busy_cursor_p) - { - if (inhibit_busy_cursor != 2) - inhibit_busy_cursor = 0; - if (!inhibit_busy_cursor) - Fx_show_busy_cursor (); - } + start_busy_cursor (); #endif nonundocount = 0; if (NILP (current_kboard->Vprefix_arg)) Fundo_boundary (); Fcommand_execute (Vthis_command, Qnil, Qnil, Qnil); + +#ifdef HAVE_X_WINDOWS + if (display_busy_cursor_p) + cancel_busy_cursor (); +#endif } directly_done: ; current_kboard->Vlast_prefix_arg = Vcurrent_prefix_arg; @@ -1643,6 +1685,7 @@ adjust_point_for_property (last_pt) if (check_display && PT > BEGV && PT < ZV && get_property_and_range (PT, Qdisplay, &val, &start, &end, Qnil) + && display_prop_intangible_p (val) && start < PT && end > PT && (last_pt <= start || last_pt >= end)) { @@ -1671,7 +1714,7 @@ static Lisp_Object safe_run_hooks_error (data) Lisp_Object data; { - Fset (Vinhibit_quit, Qnil); + return Fset (Vinhibit_quit, Qnil); } /* If we get an error while running the hook, cause the hook variable @@ -1689,37 +1732,48 @@ safe_run_hooks (hook) unbind_to (count, Qnil); } + -/* Number of seconds between polling for input. */ +/* Number of seconds between polling for input. This is a Lisp + variable that can be bound. */ + int polling_period; /* Nonzero means polling for input is temporarily suppressed. */ + int poll_suppress_count; -/* Nonzero if polling_for_input is actually being used. */ -int polling_for_input; +/* Asynchronous timer for polling. */ + +struct atimer *poll_timer; + #ifdef POLL_FOR_INPUT -/* Handle an alarm once each second and read pending input - so as to handle a C-g if it comces in. */ +/* Poll for input, so what we catch a C-g if it comes in. This + function is called from x_make_frame_visible, see comment + there. */ -SIGTYPE -input_poll_signal (signalnum) /* If we don't have an argument, */ - int signalnum; /* some compilers complain in signal calls. */ +void +poll_for_input_1 () { - /* This causes the call to start_polling at the end - to do its job. It also arranges for a quit or error - from within read_avail_input to resume polling. */ - poll_suppress_count++; if (interrupt_input_blocked == 0 && !waiting_for_input) read_avail_input (0); - /* Turn on the SIGALRM handler and request another alarm. */ - start_polling (); } -#endif +/* Timer callback function for poll_timer. TIMER is equal to + poll_timer. */ + +void +poll_for_input (timer) + struct atimer *timer; +{ + if (poll_suppress_count == 0) + poll_for_input_1 (); +} + +#endif /* POLL_FOR_INPUT */ /* Begin signals to poll for input, if they are appropriate. This function is called unconditionally from various places. */ @@ -1730,13 +1784,28 @@ start_polling () #ifdef POLL_FOR_INPUT if (read_socket_hook && !interrupt_input) { - poll_suppress_count--; - if (poll_suppress_count == 0) + /* Turn alarm handling on unconditionally. It might have + been turned off in process.c. */ + turn_on_atimers (1); + + /* If poll timer doesn't exist, are we need one with + a different interval, start a new one. */ + if (poll_timer == NULL + || EMACS_SECS (poll_timer->interval) != polling_period) { - signal (SIGALRM, input_poll_signal); - polling_for_input = 1; - alarm (polling_period); + EMACS_TIME interval; + + if (poll_timer) + cancel_atimer (poll_timer); + + EMACS_SET_SECS_USECS (interval, polling_period, 0); + poll_timer = start_atimer (ATIMER_CONTINUOUS, interval, + poll_for_input, NULL); } + + /* Let the timer's callback function poll for input + if this becomes zero. */ + --poll_suppress_count; } #endif } @@ -1760,14 +1829,7 @@ stop_polling () { #ifdef POLL_FOR_INPUT if (read_socket_hook && !interrupt_input) - { - if (poll_suppress_count == 0) - { - polling_for_input = 0; - alarm (0); - } - poll_suppress_count++; - } + ++poll_suppress_count; #endif } @@ -1805,6 +1867,7 @@ bind_polling_period (n) if (n > new) new = n; + stop_other_atimers (poll_timer); stop_polling (); specbind (Qpolling_period, make_number (new)); /* Start a new alarm with the new period. */ @@ -1850,6 +1913,82 @@ make_ctrl_char (c) return c; } +/* Display help echo in the echo area. + + HELP a string means display that string, HELP nil means clear the + help echo. If HELP is a function, call it with OBJECT and POS as + arguments; the function should return a help string or nil for + none. For all other types of HELP evaluate it to obtain a string. + + WINDOW is the window in which the help was generated, if any. + It is nil if not in a window. + + If OBJECT is a buffer, POS is the position in the buffer where the + `help-echo' text property was found. + + If OBJECT is an overlay, that overlay has a `help-echo' property, + and POS is the position in the overlay's buffer under the mouse. + + If OBJECT is a string (an overlay string or a string displayed with + the `display' property). POS is the position in that string under + the mouse. + + OK_TO_IVERWRITE_KEYSTROKE_ECHO non-zero means it's okay if the help + echo overwrites a keystroke echo currently displayed in the echo + area. + + Note: this function may only be called with HELP nil or a string + from X code running asynchronously. */ + +void +show_help_echo (help, window, object, pos, ok_to_overwrite_keystroke_echo) + Lisp_Object help, window, object, pos; + int ok_to_overwrite_keystroke_echo; +{ + if (!NILP (help) && !STRINGP (help)) + { + if (FUNCTIONP (help)) + { + Lisp_Object args[4]; + args[0] = help; + args[1] = window; + args[2] = object; + args[3] = pos; + help = call_function (4, args); + } + else + help = eval_form (help); + + if (!STRINGP (help)) + return; + } + + if (STRINGP (help) || NILP (help)) + { + if (!NILP (Vshow_help_function)) + call1 (Vshow_help_function, help); + else if (/* Don't overwrite minibuffer contents. */ + !MINI_WINDOW_P (XWINDOW (selected_window)) + /* Don't overwrite a keystroke echo. */ + && (NILP (echo_message_buffer) + || ok_to_overwrite_keystroke_echo) + /* Don't overwrite a prompt. */ + && !cursor_in_echo_area) + { + if (STRINGP (help)) + { + int count = specpdl_ptr - specpdl; + specbind (Qmessage_truncate_lines, Qt); + message3_nolog (help, XSTRING (help)->size, + STRING_MULTIBYTE (help)); + unbind_to (count, Qnil); + } + else + message (0); + } + } +} + /* Input of single characters from keyboard */ @@ -2043,19 +2182,43 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) } } - /* Message turns off echoing unless more keystrokes turn it on again. */ - if (/* There is a current message. */ + /* Message turns off echoing unless more keystrokes turn it on again. + + The code in 20.x for the condition was + + 1. echo_area_glyphs && *echo_area_glyphs + 2. && echo_area_glyphs != current_kboard->echobuf + 3. && ok_to_echo_at_next_pause != echo_area_glyphs + + (1) means there's a current message displayed + + (2) means it's not the message from echoing from the current + kboard. + + (3) There's only one place in 20.x where ok_to_echo_at_next_pause + is set to a non-null value. This is done in read_char and it is + set to echo_area_glyphs after a call to echo_char. That means + ok_to_echo_at_next_pause is either null or + current_kboard->echobuf with the appropriate current_kboard at + that time. + + So, condition (3) means in clear text ok_to_echo_at_next_pause + must be either null, or the current message isn't from echoing at + all, or it's from echoing from a different kboard than the + current one. */ + + if (/* There currently something in the echo area */ !NILP (echo_area_buffer[0]) - /* And we're not echoing from this kboard. */ - && echo_kboard != current_kboard - /* And it's either not ok to echo (ok_to_echo == NULL), or the - last char echoed was from a different kboard. */ - && ok_to_echo_at_next_pause != echo_kboard) + && (/* And it's either not from echoing. */ + !EQ (echo_area_buffer[0], echo_message_buffer) + /* Or it's an echo from a different kboard. */ + || echo_kboard != current_kboard + /* Or we explicitly allow overwriting whatever there is. */ + || ok_to_echo_at_next_pause == NULL)) cancel_echoing (); else - /* If already echoing, continue. */ echo_dash (); - + /* Try reading a character via menu prompting in the minibuf. Try this before the sit-for, because the sit-for would do the wrong thing if we are supposed to do @@ -2128,7 +2291,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) && !current_kboard->immediate_echo && this_command_key_count > 0 && ! noninteractive - && echo_keystrokes > 0 + && (FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes)) + && NILP (Fzerop (Vecho_keystrokes)) && (/* No message. */ NILP (echo_area_buffer[0]) /* Or empty message. */ @@ -2148,9 +2312,13 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) echo_now (); else { + int sec, usec; + double duration = extract_float (Vecho_keystrokes); + sec = (int) duration; + usec = (duration - sec) * 1000000; save_getcjmp (save_jump); restore_getcjmp (local_getcjmp); - tem0 = sit_for (echo_keystrokes, 0, 1, 1, 0); + tem0 = sit_for (sec, usec, 1, 1, 0); restore_getcjmp (save_jump); if (EQ (tem0, Qt) && ! CONSP (Vunread_command_events)) @@ -2455,16 +2623,21 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) if (INTEGERP (c) && ! NILP (Vinput_method_function) && (unsigned) XINT (c) >= ' ' - && (unsigned) XINT (c) < 127) + && (unsigned) XINT (c) != 127 + && (unsigned) XINT (c) < 256) { previous_echo_area_message = Fcurrent_message (); Vinput_method_previous_message = previous_echo_area_message; } - /* Now wipe the echo area. */ - if (!NILP (echo_area_buffer[0])) - safe_run_hooks (Qecho_area_clear_hook); - clear_message (1, 0); + /* Now wipe the echo area, except for help events which do their + own stuff with the echo area. */ + if (!CONSP (c) || !(EQ (Qhelp_echo, XCAR (c)))) + { + if (!NILP (echo_area_buffer[0])) + safe_run_hooks (Qecho_area_clear_hook); + clear_message (1, 0); + } reread_for_input_method: from_macro: @@ -2475,7 +2648,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) after the first event of the key sequence. */ && NILP (prev_event) && (unsigned) XINT (c) >= ' ' - && (unsigned) XINT (c) < 127) + && (unsigned) XINT (c) != 127 + && (unsigned) XINT (c) < 256) { Lisp_Object keys; int key_count; @@ -2557,21 +2731,15 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) reread_first: /* Display help if not echoing. */ - if (CONSP (c) - && EQ (XCAR (c), Qhelp_echo)) - { - Lisp_Object msg = XCDR (XCDR (c)); - - if (!NILP (Vshow_help_function)) - call1 (Vshow_help_function, msg); - else if (!echoing && !MINI_WINDOW_P (XWINDOW (selected_window))) - { - if (STRINGP (msg)) - message3_nolog (msg, XSTRING (msg)->size, STRING_MULTIBYTE (msg)); - else - message (0); - } - + if (CONSP (c) && EQ (XCAR (c), Qhelp_echo)) + { + /* (help-echo FRAME HELP WINDOW OBJECT POS). */ + Lisp_Object help, object, position, window; + help = Fnth (make_number (2), c); + window = Fnth (make_number (3), c); + object = Fnth (make_number (4), c); + position = Fnth (make_number (5), c); + show_help_echo (help, window, object, position, 0); goto retry; } @@ -2581,7 +2749,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) before_command_echo_length = echo_length (); /* Don't echo mouse motion events. */ - if (echo_keystrokes + if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes)) + && NILP (Fzerop (Vecho_keystrokes)) && ! (EVENT_HAS_PARAMETERS (c) && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qmouse_movement))) { @@ -2651,7 +2820,8 @@ record_menu_key (c) before_command_echo_length = echo_length (); /* Don't echo mouse motion events. */ - if (echo_keystrokes) + if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes)) + && NILP (Fzerop (Vecho_keystrokes))) { echo_char (c); @@ -2786,6 +2956,7 @@ tracking_off (old_value) get_input_pending (&input_pending, 1); } } + return Qnil; } DEFUN ("track-mouse", Ftrack_mouse, Strack_mouse, 0, UNEVALLED, 0, @@ -2929,6 +3100,7 @@ kbd_buffer_store_event (event) { sp->kind = no_event; sp->frame_or_window = Qnil; + sp->arg = Qnil; } } return; @@ -2976,6 +3148,11 @@ kbd_buffer_store_event (event) Discard the event if it would fill the last slot. */ if (kbd_fetch_ptr - 1 != kbd_store_ptr) { + int idx; + +#if 0 /* The selection_request_event case looks bogus, and it's error + prone to assign individual members for other events, in case + the input_event structure is changed. --2000-07-13, gerd. */ struct input_event *sp = kbd_store_ptr; sp->kind = event->kind; if (event->kind == selection_request_event) @@ -2986,22 +3163,94 @@ kbd_buffer_store_event (event) bcopy (event, (char *) sp, sizeof (*event)); } else + { sp->code = event->code; sp->part = event->part; sp->frame_or_window = event->frame_or_window; + sp->arg = event->arg; sp->modifiers = event->modifiers; sp->x = event->x; sp->y = event->y; sp->timestamp = event->timestamp; } - (XVECTOR (kbd_buffer_frame_or_window)->contents[kbd_store_ptr - - kbd_buffer] - = event->frame_or_window); +#else + *kbd_store_ptr = *event; +#endif - kbd_store_ptr++; + idx = 2 * (kbd_store_ptr - kbd_buffer); + ASET (kbd_buffer_gcpro, idx, event->frame_or_window); + ASET (kbd_buffer_gcpro, idx + 1, event->arg); + ++kbd_store_ptr; } } + + +/* Generate HELP_EVENT input_events in BUFP which has roon for + SIZE events. If there's not enough room in BUFP, ignore this + event. + + HELP is the help form. + + FRAME is the frame on which the help is generated. OBJECT is the + Lisp object where the help was found (a buffer, a string, an + overlay, or nil if neither from a string nor from a buffer. POS is + the position within OBJECT where the help was found. + + Value is the number of input_events generated. */ + +int +gen_help_event (bufp, size, help, frame, window, object, pos) + struct input_event *bufp; + int size; + Lisp_Object help, frame, object, window; + int pos; +{ + int nevents_stored = 0; + + if (size >= 2) + { + bufp->kind = HELP_EVENT; + bufp->frame_or_window = frame; + bufp->arg = object; + bufp->x = make_number (pos); + bufp->code = 0; + + ++bufp; + bufp->kind = HELP_EVENT; + bufp->frame_or_window = WINDOWP (window) ? window : frame; + bufp->arg = help; + bufp->code = 1; + nevents_stored = 2; + } + + return nevents_stored; +} + + +/* Store HELP_EVENTs for HELP on FRAME in the input queue. */ + +void +kbd_buffer_store_help_event (frame, help) + Lisp_Object frame, help; +{ + struct input_event event; + + event.kind = HELP_EVENT; + event.frame_or_window = frame; + event.arg = Qnil; + event.x = make_number (0); + event.code = 0; + kbd_buffer_store_event (&event); + + event.kind = HELP_EVENT; + event.frame_or_window = frame; + event.arg = help; + event.x = make_number (0); + event.code = 1; + kbd_buffer_store_event (&event); +} + /* Discard any mouse events in the event buffer by setting them to no_event. */ @@ -3024,7 +3273,49 @@ discard_mouse_events () } } } + + +/* Return non-zero if there are any real events waiting in the event + buffer, not counting `no_event's. + + If DISCARD is non-zero, discard no_event events at the front of + the input queue, possibly leaving the input queue empty if there + are no real input events. */ + +int +kbd_buffer_events_waiting (discard) + int discard; +{ + struct input_event *sp; + + for (sp = kbd_fetch_ptr; + sp != kbd_store_ptr && sp->kind == no_event; + ++sp) + { + if (sp == kbd_buffer + KBD_BUFFER_SIZE) + sp = kbd_buffer; + } + + if (discard) + kbd_fetch_ptr = sp; + + return sp != kbd_store_ptr && sp->kind != no_event; +} + +/* Clear input event EVENT. */ + +static INLINE void +clear_event (event) + struct input_event *event; +{ + int idx = 2 * (event - kbd_buffer); + ASET (kbd_buffer_gcpro, idx, Qnil); + ASET (kbd_buffer_gcpro, idx + 1, Qnil); + event->kind = no_event; +} + + /* Read one event from the event buffer, waiting if necessary. The value is a Lisp object representing the event. The value is nil for an event that should be ignored, @@ -3222,15 +3513,51 @@ kbd_buffer_get_event (kbp, used_mouse_menu) kbd_fetch_ptr = event + 1; else if (event->kind == HELP_EVENT) { - /* The car of event->frame_or_window is a frame, - the cdr is the help to display. */ - obj = Fcons (Qhelp_echo, event->frame_or_window); + /* There are always two HELP_EVENTs in the input queue. */ + Lisp_Object object, position, help, frame, window; + + xassert (event->code == 0); + frame = event->frame_or_window; + object = event->arg; + position = event->x; + clear_event (event); + + kbd_fetch_ptr = event + 1; + event = ((kbd_fetch_ptr < kbd_buffer + KBD_BUFFER_SIZE) + ? kbd_fetch_ptr + : kbd_buffer); + xassert (event->code == 1); + help = event->arg; + window = event->frame_or_window; + if (!WINDOWP (window)) + window = Qnil; + obj = Fcons (Qhelp_echo, + list5 (frame, help, window, object, position)); + clear_event (event); + kbd_fetch_ptr = event + 1; + } + else if (event->kind == FOCUS_IN_EVENT) + { + /* Notification of a FocusIn event. The frame receiving the + focus is in event->frame_or_window. Generate a + switch-frame event if necessary. */ + Lisp_Object frame, focus; + + frame = event->frame_or_window; + focus = FRAME_FOCUS_FRAME (XFRAME (frame)); + if (FRAMEP (focus)) + frame = focus; + + if (!EQ (frame, internal_last_event_frame) + && !EQ (frame, selected_frame)) + obj = make_lispy_switch_frame (frame); + internal_last_event_frame = frame; kbd_fetch_ptr = event + 1; } - /* If this event is on a different frame, return a switch-frame this - time, and leave the event in the queue for next time. */ else { + /* If this event is on a different frame, return a switch-frame this + time, and leave the event in the queue for next time. */ Lisp_Object frame; Lisp_Object focus; @@ -3254,25 +3581,25 @@ kbd_buffer_get_event (kbp, used_mouse_menu) if (NILP (obj)) { + int idx; + obj = make_lispy_event (event); + #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) /* If this was a menu selection, then set the flag to inhibit writing to last_nonmenu_event. Don't do this if the event we're returning is (menu-bar), though; that indicates the beginning of the menu sequence, and we might as well leave that as the `event with parameters' for this selection. */ - if ((event->kind == menu_bar_event - || event->kind == TOOL_BAR_EVENT) - && !(CONSP (obj) && EQ (XCAR (obj), Qmenu_bar)) - && !(CONSP (obj) && EQ (XCAR (obj), Qtool_bar)) - && used_mouse_menu) + if (used_mouse_menu + && !EQ (event->frame_or_window, event->arg) + && (event->kind == MENU_BAR_EVENT + || event->kind == TOOL_BAR_EVENT)) *used_mouse_menu = 1; #endif /* Wipe out this event, to catch bugs. */ - event->kind = no_event; - XVECTOR (kbd_buffer_frame_or_window)->contents[event - kbd_buffer] = Qnil; - + clear_event (event); kbd_fetch_ptr = event + 1; } } @@ -3588,7 +3915,7 @@ timer_check (do_it_now) } vector = XVECTOR (chosen_timer)->contents; - /* If timer is rupe, run it if it hasn't been run. */ + /* If timer is ripe, run it if it hasn't been run. */ if (EMACS_TIME_NEG_P (difference) || (EMACS_SECS (difference) == 0 && EMACS_USECS (difference) == 0)) @@ -3597,9 +3924,6 @@ timer_check (do_it_now) { int was_locked = single_kboard; int count = specpdl_ptr - specpdl; -#ifdef HAVE_WINDOW_SYSTEM - int old_inhibit_busy_cursor = inhibit_busy_cursor; -#endif /* Mark the timer as triggered to prevent problems if the lisp code fails to reschedule it right. */ @@ -3607,17 +3931,9 @@ timer_check (do_it_now) specbind (Qinhibit_quit, Qt); -#ifdef HAVE_WINDOW_SYSTEM - inhibit_busy_cursor = 2; -#endif - call1 (Qtimer_event_handler, chosen_timer); timers_run++; -#ifdef HAVE_WINDOW_SYSTEM - inhibit_busy_cursor = old_inhibit_busy_cursor; -#endif - unbind_to (count, Qnil); /* Resume allowing input from any kboard, if that was true before. */ @@ -4054,10 +4370,7 @@ static char *iso_lispy_function_keys[] = #endif /* not HAVE_NTGUI */ -static char *lispy_mouse_names[] = -{ - "mouse-1", "mouse-2", "mouse-3", "mouse-4", "mouse-5" -}; +Lisp_Object Vlispy_mouse_stem; #ifdef WINDOWSNT /* mouse-wheel events are generated by the wheel on devices such as @@ -4172,6 +4485,14 @@ make_lispy_event (event) return lispy_c; } + case multibyte_char_keystroke: + { + Lisp_Object lispy_c; + + XSETFASTINT (lispy_c, event->code); + return lispy_c; + } + /* A function key. The symbol may need to have modifier prefixes tacked onto it. */ case non_ascii_keystroke: @@ -4243,9 +4564,6 @@ make_lispy_event (event) Lisp_Object *start_pos_ptr; Lisp_Object start_pos; - if (button < 0 || button >= NUM_MOUSE_BUTTONS) - abort (); - /* Build the position as appropriate for this mouse click. */ if (event->kind == mouse_click) { @@ -4397,6 +4715,13 @@ make_lispy_event (event) } #endif /* not USE_TOOLKIT_SCROLL_BARS */ + if (button >= XVECTOR (button_down_location)->size) + { + button_down_location = larger_vector (button_down_location, + button + 1, Qnil); + mouse_syms = larger_vector (mouse_syms, button + 1, Qnil); + } + start_pos_ptr = &XVECTOR (button_down_location)->contents[button]; start_pos = *start_pos_ptr; @@ -4486,10 +4811,10 @@ make_lispy_event (event) head = modify_event_symbol (button, event->modifiers, - Qmouse_click, Qnil, - lispy_mouse_names, &mouse_syms, - (sizeof (lispy_mouse_names) - / sizeof (lispy_mouse_names[0]))); + Qmouse_click, Vlispy_mouse_stem, + NULL, + &mouse_syms, + XVECTOR (mouse_syms)->size); if (event->modifiers & drag_modifier) return Fcons (head, Fcons (start_pos, @@ -4547,10 +4872,10 @@ make_lispy_event (event) /* Get the symbol we should use for the mouse click. */ head = modify_event_symbol (event->code, event->modifiers, - Qmouse_click, Qnil, - lispy_mouse_names, &mouse_syms, - (sizeof (lispy_mouse_names) - / sizeof (lispy_mouse_names[0]))); + Qmouse_click, + Vlispy_mouse_stem, + NULL, &mouse_syms, + XVECTOR (mouse_syms)->size); return Fcons (head, Fcons (position, Qnil)); } @@ -4565,9 +4890,6 @@ make_lispy_event (event) Lisp_Object *start_pos_ptr; Lisp_Object start_pos; - if (button < 0 || button >= NUM_MOUSE_BUTTONS) - abort (); - { Lisp_Object window; Lisp_Object portion_whole; @@ -4594,10 +4916,10 @@ make_lispy_event (event) head = modify_event_symbol (button, event->modifiers, - Qmouse_click, Qnil, - lispy_mouse_names, &mouse_syms, - (sizeof (lispy_mouse_names) - / sizeof (lispy_mouse_names[0]))); + Qmouse_click, + Vlispy_mouse_stem, + NULL, &mouse_syms, + XVECTOR (mouse_syms)->size); return Fcons (head, Fcons (position, Qnil)); @@ -4630,7 +4952,8 @@ make_lispy_event (event) int pixcolumn, pixrow; column -= XINT (XWINDOW (window)->left); row -= XINT (XWINDOW (window)->top); - glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow); + glyph_to_pixel_coords (XWINDOW(window), column, row, + &pixcolumn, &pixrow); XSETINT (event->x, pixcolumn); XSETINT (event->y, pixrow); @@ -4643,7 +4966,7 @@ make_lispy_event (event) else XSETINT (posn, buffer_posn_from_coords (XWINDOW (window), - column, row)); + &column, &row)); } { @@ -4747,25 +5070,26 @@ make_lispy_event (event) #endif /* HAVE_MOUSE */ #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) - case menu_bar_event: - /* The event value is in the cdr of the frame_or_window slot. */ - if (!CONSP (event->frame_or_window)) - abort (); - return XCDR (event->frame_or_window); + case MENU_BAR_EVENT: + if (EQ (event->arg, event->frame_or_window)) + /* This is the prefix key. We translate this to + `(menu_bar)' because the code in keyboard.c for menu + events, which we use, relies on this. */ + return Fcons (Qmenu_bar, Qnil); + return event->arg; #endif case TOOL_BAR_EVENT: - { - Lisp_Object key; - if (!CONSP (event->frame_or_window)) - abort (); - key = XCDR (event->frame_or_window); - if (SYMBOLP (key)) - key = apply_modifiers (event->modifiers, key); - return key; - } - - case user_signal: + if (EQ (event->arg, event->frame_or_window)) + /* This is the prefix key. We translate this to + `(tool_bar)' because the code in keyboard.c for menu + events, which we use, relies on this. */ + return Fcons (Qtool_bar, Qnil); + else if (SYMBOLP (event->arg)) + return apply_modifiers (event->modifiers, event->arg); + return event->arg; + + case USER_SIGNAL_EVENT: /* A user signal. */ return *lispy_user_signals[event->code]; @@ -5187,8 +5511,11 @@ reorder_modifiers (symbol) is the name of the i'th symbol. TABLE_SIZE is the number of elements in the table. - Alternatively, NAME_ALIST is an alist mapping codes into symbol names. - NAME_ALIST is used if it is non-nil; otherwise NAME_TABLE is used. + Alternatively, NAME_ALIST_OR_STEM is either an alist mapping codes + into symbol names, or a string specifying a name stem used to + construct a symbol name or the form `STEM-N', where N is the decimal + representation of SYMBOL_NUM. NAME_ALIST_OR_STEM is used if it is + non-nil; otherwise NAME_TABLE is used. SYMBOL_TABLE should be a pointer to a Lisp_Object whose value will persist between calls to modify_event_symbol that it can use to @@ -5208,12 +5535,12 @@ reorder_modifiers (symbol) in the symbol's name. */ static Lisp_Object -modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist, +modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist_or_stem, name_table, symbol_table, table_size) int symbol_num; unsigned modifiers; Lisp_Object symbol_kind; - Lisp_Object name_alist; + Lisp_Object name_alist_or_stem; char **name_table; Lisp_Object *symbol_table; unsigned int table_size; @@ -5253,8 +5580,16 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist, if (NILP (value)) { /* No; let's create it. */ - if (!NILP (name_alist)) - value = Fcdr_safe (Fassq (symbol_int, name_alist)); + if (CONSP (name_alist_or_stem)) + value = Fcdr_safe (Fassq (symbol_int, name_alist_or_stem)); + else if (STRINGP (name_alist_or_stem)) + { + int len = STRING_BYTES (XSTRING (name_alist_or_stem)); + char *buf = (char *) alloca (len + 50); + sprintf (buf, "%s-%d", XSTRING (name_alist_or_stem)->data, + XINT (symbol_int) + 1); + value = intern (buf); + } else if (name_table != 0 && name_table[symbol_num]) value = intern (name_table[symbol_num]); @@ -5528,6 +5863,7 @@ record_asynch_buffer_change () event.kind = buffer_switch_event; event.frame_or_window = Qnil; + event.arg = Qnil; #ifdef subprocesses /* We don't need a buffer-switch event unless Emacs is waiting for input. @@ -5689,6 +6025,7 @@ read_avail_input (expected) buf[i].code = cbuf[i]; buf[i].frame_or_window = selected_frame; + buf[i].arg = Qnil; } } @@ -5866,11 +6203,18 @@ menu_bar_items (old) } else { - /* No, so use major and minor mode keymaps. */ + /* No, so use major and minor mode keymaps and keymap property. */ + int extra_maps = 2; + Lisp_Object map = get_local_map (PT, current_buffer, keymap); + if (!NILP (map)) + extra_maps = 3; nmaps = current_minor_maps (NULL, &tmaps); - maps = (Lisp_Object *) alloca ((nmaps + 2) * sizeof (maps[0])); + maps = (Lisp_Object *) alloca ((nmaps + extra_maps) + * sizeof (maps[0])); bcopy (tmaps, maps, nmaps * sizeof (maps[0])); - maps[nmaps++] = get_local_map (PT, current_buffer); + if (!NILP (map)) + maps[nmaps++] = get_local_map (PT, current_buffer, keymap); + maps[nmaps++] = get_local_map (PT, current_buffer, local_map); } maps[nmaps++] = current_global_map; } @@ -6150,7 +6494,7 @@ parse_menu_item (item, notreal, inmenubar) item = XCDR (item); } - /* Maybee key binding cache. */ + /* Maybe key binding cache. */ if (CONSP (item) && CONSP (XCAR (item)) && (NILP (XCAR (XCAR (item))) || VECTORP (XCAR (XCAR (item))))) @@ -6518,11 +6862,18 @@ tool_bar_items (reuse, nitems) } else { - /* No, so use major and minor mode keymaps. */ + /* No, so use major and minor mode keymaps and keymap property. */ + int extra_maps = 2; + Lisp_Object map = get_local_map (PT, current_buffer, keymap); + if (!NILP (map)) + extra_maps = 3; nmaps = current_minor_maps (NULL, &tmaps); - maps = (Lisp_Object *) alloca ((nmaps + 2) * sizeof (maps[0])); + maps = (Lisp_Object *) alloca ((nmaps + extra_maps) + * sizeof (maps[0])); bcopy (tmaps, maps, nmaps * sizeof (maps[0])); - maps[nmaps++] = get_local_map (PT, current_buffer); + if (!NILP (map)) + maps[nmaps++] = get_local_map (PT, current_buffer, keymap); + maps[nmaps++] = get_local_map (PT, current_buffer, local_map); } /* Add global keymap at the end. */ @@ -7070,7 +7421,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps) char_matches = (XINT (upcased_event) == XSTRING (s)->data[0] || XINT (downcased_event) == XSTRING (s)->data[0]); if (! char_matches) - desc = Fsingle_key_description (event); + desc = Fsingle_key_description (event, Qnil); tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ]; @@ -7215,7 +7566,7 @@ follow_key (key, nmaps, current, defs, next) followed by the corresponding non-meta character. Put the results into DEFS, since we are going to alter that anyway. Do not alter CURRENT or NEXT. */ - if (INTEGERP (key) && (XINT (key) & CHAR_META)) + if (INTEGERP (key) && (XUINT (key) & CHAR_META)) { for (i = 0; i < nmaps; i++) if (! NILP (current[i])) @@ -7247,7 +7598,7 @@ follow_key (key, nmaps, current, defs, next) else map = current[i]; - defs[i] = get_keyelt (access_keymap (map, key, 1, 0), 0); + defs[i] = get_keyelt (access_keymap (map, key, 1, 0), 1); if (! NILP (defs[i])) first_binding = i; } @@ -7336,6 +7687,10 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, /* The local map to start out with at start of key sequence. */ Lisp_Object orig_local_map; + /* The map from the `keymap' property to start out with at start of + key sequence. */ + Lisp_Object orig_keymap; + /* 1 if we have already considered switching to the local-map property of the place where a mouse click occurred. */ int localized_local_map = 0; @@ -7431,7 +7786,9 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, { if (!NILP (prompt)) echo_prompt (XSTRING (prompt)->data); - else if (cursor_in_echo_area && echo_keystrokes) + else if (cursor_in_echo_area + && (FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes)) + && NILP (Fzerop (Vecho_keystrokes))) /* This doesn't put in a dash if the echo buffer is empty, so you don't always see a dash hanging out in the minibuffer. */ echo_dash (); @@ -7455,7 +7812,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, &junk); #endif /* GOBBLE_FIRST_EVENT */ - orig_local_map = get_local_map (PT, current_buffer); + orig_local_map = get_local_map (PT, current_buffer, local_map); + orig_keymap = get_local_map (PT, current_buffer, keymap); /* We jump here when the key sequence has been thoroughly changed, and we need to rescan it starting from the beginning. When we jump here, @@ -7491,14 +7849,21 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, } else { + int extra_maps = 2; nmaps = current_minor_maps (0, &maps); - if (nmaps + 2 > nmaps_allocated) + if (!NILP (orig_keymap)) + extra_maps = 3; + if (nmaps + extra_maps > nmaps_allocated) { - submaps = (Lisp_Object *) alloca ((nmaps+2) * sizeof (submaps[0])); - defs = (Lisp_Object *) alloca ((nmaps+2) * sizeof (defs[0])); - nmaps_allocated = nmaps + 2; + submaps = (Lisp_Object *) alloca ((nmaps+extra_maps) + * sizeof (submaps[0])); + defs = (Lisp_Object *) alloca ((nmaps+extra_maps) + * sizeof (defs[0])); + nmaps_allocated = nmaps + extra_maps; } bcopy (maps, submaps, nmaps * sizeof (submaps[0])); + if (!NILP (orig_keymap)) + submaps[nmaps++] = orig_keymap; submaps[nmaps++] = orig_local_map; } submaps[nmaps++] = current_global_map; @@ -7577,7 +7942,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, { key = keybuf[t]; add_command_key (key); - if (echo_keystrokes) + if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes)) + && NILP (Fzerop (Vecho_keystrokes))) echo_char (key); } @@ -7616,7 +7982,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, interrupted_kboard->kbd_queue); } mock_input = 0; - orig_local_map = get_local_map (PT, current_buffer); + orig_local_map = get_local_map (PT, current_buffer, local_map); + orig_keymap = get_local_map (PT, current_buffer, keymap); goto replay_sequence; } #endif @@ -7661,7 +8028,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, Fset_buffer (XWINDOW (selected_window)->buffer); } - orig_local_map = get_local_map (PT, current_buffer); + orig_local_map = get_local_map (PT, current_buffer, local_map); + orig_keymap = get_local_map (PT, current_buffer, keymap); goto replay_sequence; } @@ -7675,7 +8043,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, keybuf[t++] = key; mock_input = t; Vquit_flag = Qnil; - orig_local_map = get_local_map (PT, current_buffer); + orig_local_map = get_local_map (PT, current_buffer, local_map); + orig_keymap = get_local_map (PT, current_buffer, keymap); goto replay_sequence; } @@ -7760,8 +8129,12 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, if (! FRAME_LIVE_P (XFRAME (selected_frame))) Fkill_emacs (Qnil); - set_buffer_internal (XBUFFER (XWINDOW (window)->buffer)); - orig_local_map = get_local_map (PT, current_buffer); + set_buffer_internal (XBUFFER (XWINDOW + (window)->buffer) +); + orig_local_map = get_local_map (PT, current_buffer, + local_map); + orig_keymap = get_local_map (PT, current_buffer, keymap); goto replay_sequence; } @@ -7782,13 +8155,24 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, if (INTEGERP (pos) && XINT (pos) >= BEG && XINT (pos) <= Z) { - map_here = get_local_map (XINT (pos), current_buffer); + map_here = get_local_map (XINT (pos), + current_buffer, local_map); if (!EQ (map_here, orig_local_map)) { orig_local_map = map_here; keybuf[t] = key; mock_input = t + 1; + goto replay_sequence; + } + map_here = get_local_map (XINT (pos), + current_buffer, keymap); + if (!EQ (map_here, orig_keymap)) + { + orig_keymap = map_here; + keybuf[t] = key; + mock_input = t + 1; + goto replay_sequence; } } @@ -7814,21 +8198,23 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, reconsider the key sequence with that keymap. */ if (CONSP (POSN_STRING (EVENT_START (key)))) { - Lisp_Object string, pos, map; + Lisp_Object string, pos, map, map2; string = POSN_STRING (EVENT_START (key)); pos = XCDR (string); string = XCAR (string); - - if (pos >= 0 - && pos < XSTRING (string)->size - && (map = Fget_text_property (pos, Qlocal_map, - string), - !NILP (map))) - { - orig_local_map = map; - goto replay_sequence; - } + if (XINT (pos) >= 0 + && XINT (pos) < XSTRING (string)->size) + { + map = Fget_text_property (pos, Qlocal_map, string); + if (!NILP (map)) + orig_local_map = map; + map2 = Fget_text_property (pos, Qkeymap, string); + if (!NILP (map2)) + orig_keymap = map2; + if (!NILP (map) || !NILP (map2)) + goto replay_sequence; + } } goto replay_key; @@ -8035,7 +8421,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, key = keybuf[fkey_end++]; /* Look up meta-characters by prefixing them with meta_prefix_char. I hate this. */ - if (INTEGERP (key) && XINT (key) & meta_modifier) + if (INTEGERP (key) && XUINT (key) & meta_modifier) { fkey_next = get_keymap_1 @@ -8159,7 +8545,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, key = keybuf[keytran_end++]; /* Look up meta-characters by prefixing them with meta_prefix_char. I hate this. */ - if (INTEGERP (key) && XINT (key) & meta_modifier) + if (INTEGERP (key) && XUINT (key) & meta_modifier) { keytran_next = get_keymap_1 @@ -8366,7 +8752,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, Better ideas? */ for (; t < mock_input; t++) { - if (echo_keystrokes) + if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes)) + && NILP (Fzerop (Vecho_keystrokes))) echo_char (keybuf[t]); add_command_key (keybuf[t]); } @@ -8459,10 +8846,20 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0, this_single_command_key_start = 0; } +#ifdef HAVE_X_WINDOWS + if (display_busy_cursor_p) + cancel_busy_cursor (); +#endif + i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])), prompt, ! NILP (dont_downcase_last), ! NILP (can_return_switch_frame), 0); +#ifdef HAVE_X_WINDOWS + if (display_busy_cursor_p) + start_busy_cursor (); +#endif + if (i == -1) { Vquit_flag = Qt; @@ -8504,10 +8901,20 @@ DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector, this_single_command_key_start = 0; } +#ifdef HAVE_X_WINDOWS + if (display_busy_cursor_p) + cancel_busy_cursor (); +#endif + i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])), prompt, ! NILP (dont_downcase_last), ! NILP (can_return_switch_frame), 0); +#ifdef HAVE_X_WINDOWS + if (display_busy_cursor_p) + start_busy_cursor (); +#endif + if (i == -1) { Vquit_flag = Qt; @@ -8787,11 +9194,18 @@ current_active_maps (maps_p) } else { - /* No, so use major and minor mode keymaps. */ + /* No, so use major and minor mode keymaps and keymap property. */ + int extra_maps = 2; + Lisp_Object map = get_local_map (PT, current_buffer, keymap); + if (!NILP (map)) + extra_maps = 3; nmaps = current_minor_maps (NULL, &tmaps); - maps = (Lisp_Object *) xmalloc ((nmaps + 2) * sizeof (maps[0])); + maps = (Lisp_Object *) alloca ((nmaps + extra_maps) + * sizeof (maps[0])); bcopy (tmaps, maps, nmaps * sizeof (maps[0])); - maps[nmaps++] = get_local_map (PT, current_buffer); + if (!NILP (map)) + maps[nmaps++] = get_local_map (PT, current_buffer, keymap); + maps[nmaps++] = get_local_map (PT, current_buffer, local_map); } maps[nmaps++] = current_global_map; @@ -9019,7 +9433,7 @@ Also cancel any kbd macro being defined.") discard_tty_input (); kbd_fetch_ptr = kbd_store_ptr; - Ffillarray (kbd_buffer_frame_or_window, Qnil); + Ffillarray (kbd_buffer_gcpro, Qnil); input_pending = 0; return Qnil; @@ -9103,20 +9517,25 @@ stuff_buffered_input (stuffstring) stuff_char (*p++); stuff_char ('\n'); } + /* Anything we have read ahead, put back for the shell to read. */ /* ?? What should this do when we have multiple keyboards?? Should we ignore anything that was typed in at the "wrong" kboard? */ for (; kbd_fetch_ptr != kbd_store_ptr; kbd_fetch_ptr++) { + int idx; + if (kbd_fetch_ptr == kbd_buffer + KBD_BUFFER_SIZE) kbd_fetch_ptr = kbd_buffer; if (kbd_fetch_ptr->kind == ascii_keystroke) stuff_char (kbd_fetch_ptr->code); + kbd_fetch_ptr->kind = no_event; - (XVECTOR (kbd_buffer_frame_or_window)->contents[kbd_fetch_ptr - - kbd_buffer] - = Qnil); + idx = 2 * (kbd_fetch_ptr - kbd_buffer); + ASET (kbd_buffer_gcpro, idx, Qnil); + ASET (kbd_buffer_gcpro, idx + 1, Qnil); } + input_pending = 0; #endif #endif /* BSD_SYSTEM and not BSD4_1 */ @@ -9146,16 +9565,17 @@ clear_waiting_for_input () } /* This routine is called at interrupt level in response to C-G. - If interrupt_input, this is the handler for SIGINT. - Otherwise, it is called from kbd_buffer_store_event, - in handling SIGIO or SIGTINT. + + If interrupt_input, this is the handler for SIGINT. Otherwise, it + is called from kbd_buffer_store_event, in handling SIGIO or + SIGTINT. - If `waiting_for_input' is non zero, then unless `echoing' is nonzero, - immediately throw back to read_char. + If `waiting_for_input' is non zero, then unless `echoing' is + nonzero, immediately throw back to read_char. - Otherwise it sets the Lisp variable quit-flag not-nil. - This causes eval to throw, when it gets a chance. - If quit-flag is already non-nil, it stops the job right away. */ + Otherwise it sets the Lisp variable quit-flag not-nil. This causes + eval to throw, when it gets a chance. If quit-flag is already + non-nil, it stops the job right away. */ SIGTYPE interrupt_signal (signalnum) /* If we don't have an argument, */ @@ -9497,8 +9917,7 @@ init_keyboard () recent_keys_index = 0; kbd_fetch_ptr = kbd_buffer; kbd_store_ptr = kbd_buffer; - kbd_buffer_frame_or_window - = Fmake_vector (make_number (KBD_BUFFER_SIZE), Qnil); + kbd_buffer_gcpro = Fmake_vector (make_number (2 * KBD_BUFFER_SIZE), Qnil); #ifdef HAVE_MOUSE do_mouse_tracking = Qnil; #endif @@ -9515,11 +9934,6 @@ init_keyboard () wipe_kboard (current_kboard); init_kboard (current_kboard); - if (initialized) - Ffillarray (kbd_buffer_frame_or_window, Qnil); - - kbd_buffer_frame_or_window - = Fmake_vector (make_number (KBD_BUFFER_SIZE), Qnil); if (!noninteractive && !read_socket_hook && NILP (Vwindow_system)) { signal (SIGINT, interrupt_signal); @@ -9581,6 +9995,9 @@ struct event_head head_table[] = { void syms_of_keyboard () { + Vlispy_mouse_stem = build_string ("mouse"); + staticpro (&Vlispy_mouse_stem); + /* Tool-bars. */ QCimage = intern (":image"); staticpro (&QCimage); @@ -9732,6 +10149,8 @@ syms_of_keyboard () Fset (Qinput_method_exit_on_first_char, Qnil); Fset (Qinput_method_use_echo_area, Qnil); + last_point_position_buffer = Qnil; + { struct event_head *p; @@ -9746,8 +10165,10 @@ syms_of_keyboard () } } - button_down_location = Fmake_vector (make_number (NUM_MOUSE_BUTTONS), Qnil); + button_down_location = Fmake_vector (make_number (1), Qnil); staticpro (&button_down_location); + mouse_syms = Fmake_vector (make_number (1), Qnil); + staticpro (&mouse_syms); { int i; @@ -9773,9 +10194,8 @@ syms_of_keyboard () Fset (Qextended_command_history, Qnil); staticpro (&Qextended_command_history); - kbd_buffer_frame_or_window - = Fmake_vector (make_number (KBD_BUFFER_SIZE), Qnil); - staticpro (&kbd_buffer_frame_or_window); + kbd_buffer_gcpro = Fmake_vector (make_number (2 * KBD_BUFFER_SIZE), Qnil); + staticpro (&kbd_buffer_gcpro); accent_key_syms = Qnil; staticpro (&accent_key_syms); @@ -9783,9 +10203,6 @@ syms_of_keyboard () func_key_syms = Qnil; staticpro (&func_key_syms); - mouse_syms = Qnil; - staticpro (&mouse_syms); - #ifdef WINDOWSNT mouse_wheel_syms = Qnil; staticpro (&mouse_wheel_syms); @@ -9911,9 +10328,10 @@ After auto-saving due to this many seconds of idle time,\n\ Emacs also does a garbage collection if that seems to be warranted."); XSETFASTINT (Vauto_save_timeout, 30); - DEFVAR_INT ("echo-keystrokes", &echo_keystrokes, - "*Nonzero means echo unfinished commands after this many seconds of pause."); - echo_keystrokes = 1; + DEFVAR_LISP ("echo-keystrokes", &Vecho_keystrokes, + "*Nonzero means echo unfinished commands after this many seconds of pause.\n\ +The value may be integer or floating point."); + Vecho_keystrokes = make_number (1); DEFVAR_INT ("polling-period", &polling_period, "*Interval between polling for input during Lisp execution.\n\