X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/0b7d6b026eb2cd69a90a9af41a4fca24389c5e47..3e71e4379ce7b53afe51ead4c94e6bb016bc6e7a:/src/keyboard.c diff --git a/src/keyboard.c b/src/keyboard.c index 02bc7d2a0b..8901ff055e 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1,14 +1,14 @@ /* Keyboard and mouse input; editor command loop. -Copyright (C) 1985-1989, 1993-1997, 1999-2015 Free Software Foundation, +Copyright (C) 1985-1989, 1993-1997, 1999-2016 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -64,10 +64,17 @@ along with GNU Emacs. If not, see . */ #include #include +#include + #ifdef HAVE_WINDOW_SYSTEM #include TERM_HEADER #endif /* HAVE_WINDOW_SYSTEM */ +/* Work around GCC bug 54561. */ +#if GNUC_PREREQ (4, 3, 0) +# pragma GCC diagnostic ignored "-Wclobbered" +#endif + /* Variables for blockinput.h: */ /* Positive if interrupt input is blocked right now. */ @@ -195,8 +202,9 @@ Lisp_Object unread_switch_frame; /* Last size recorded for a current buffer which is not a minibuffer. */ static ptrdiff_t last_non_minibuf_size; -/* Total number of times read_char has returned, modulo UINTMAX_MAX + 1. */ uintmax_t num_input_events; +ptrdiff_t point_before_last_command_or_undo; +struct buffer *buffer_before_last_command_or_undo; /* Value of num_nonmacro_input_events as of last auto save. */ @@ -424,6 +432,14 @@ kset_system_key_syms (struct kboard *kb, Lisp_Object val) } +static bool +echo_keystrokes_p (void) +{ + return (FLOATP (Vecho_keystrokes) ? XFLOAT_DATA (Vecho_keystrokes) > 0.0 + : INTEGERP (Vecho_keystrokes) ? XINT (Vecho_keystrokes) > 0 + : false); +} + /* Add C to the echo string, without echoing it immediately. C can be a character, which is pretty-printed, or a symbol, whose name is printed. */ @@ -565,7 +581,9 @@ echo_update (void) static void echo_now (void) { - if (!current_kboard->immediate_echo) + if (!current_kboard->immediate_echo + /* This test breaks calls that use `echo_now' to display the echo_prompt. + && echo_keystrokes_p () */) { current_kboard->immediate_echo = true; echo_update (); @@ -668,6 +686,14 @@ recursive_edit_1 (void) specbind (Qinhibit_redisplay, Qnil); redisplaying_p = 0; + /* This variable stores buffers that have changed so that an undo + boundary can be added. specbind this so that changes in the + recursive edit will not result in undo boundaries in buffers + changed before we entered there recursive edit. + See Bug #23632. + */ + specbind (Qundo_auto__undoably_changed_buffers, Qnil); + val = command_loop (); if (EQ (val, Qt)) Fsignal (Qquit, Qnil); @@ -1233,9 +1259,6 @@ static void adjust_point_for_property (ptrdiff_t, bool); Lisp_Object command_loop_1 (void) { - Lisp_Object cmd; - Lisp_Object keybuf[30]; - int i; EMACS_INT prev_modiff = 0; struct buffer *prev_buffer = NULL; bool already_adjusted = 0; @@ -1279,6 +1302,10 @@ command_loop_1 (void) while (1) { + Lisp_Object cmd; + Lisp_Object keybuf[30]; + int i; + if (! FRAME_LIVE_P (XFRAME (selected_frame))) Fkill_emacs (Qnil); @@ -2108,7 +2135,7 @@ read_event_from_main_queue (struct timespec *end_time, { Lisp_Object c = Qnil; sys_jmp_buf save_jump; - KBOARD *kb IF_LINT (= NULL); + KBOARD *kb; start: @@ -2179,8 +2206,8 @@ read_decoded_event_from_main_queue (struct timespec *end_time, Lisp_Object prev_event, bool *used_mouse_menu) { -#define MAX_ENCODED_BYTES 16 #ifndef WINDOWSNT +#define MAX_ENCODED_BYTES 16 Lisp_Object events[MAX_ENCODED_BYTES]; int n = 0; #endif @@ -2266,13 +2293,6 @@ read_decoded_event_from_main_queue (struct timespec *end_time, } } -static bool -echo_keystrokes_p (void) -{ - return (FLOATP (Vecho_keystrokes) ? XFLOAT_DATA (Vecho_keystrokes) > 0.0 - : INTEGERP (Vecho_keystrokes) ? XINT (Vecho_keystrokes) > 0 : false); -} - /* Read a character from the keyboard; call the redisplay if needed. */ /* commandflag 0 means do not autosave, but do redisplay. -1 means do not redisplay, but do autosave. @@ -2522,7 +2542,7 @@ read_char (int commandflag, Lisp_Object map, if (KEYMAPP (map) && INTERACTIVE && !NILP (prev_event) && ! EVENT_HAS_PARAMETERS (prev_event) /* Don't bring up a menu if we already have another event. */ - && NILP (Vunread_command_events) + && !CONSP (Vunread_command_events) && !detect_input_pending_run_timers (0)) { c = read_char_minibuf_menu_prompt (commandflag, map); @@ -2653,7 +2673,7 @@ read_char (int commandflag, Lisp_Object map, && !EQ (XCAR (prev_event), Qmenu_bar) && !EQ (XCAR (prev_event), Qtool_bar) /* Don't bring up a menu if we already have another event. */ - && NILP (Vunread_command_events)) + && !CONSP (Vunread_command_events)) { c = read_char_x_menu_prompt (map, prev_event, used_mouse_menu); @@ -2827,10 +2847,19 @@ read_char (int commandflag, Lisp_Object map, last_input_event = c; call4 (Qcommand_execute, tem, Qnil, Fvector (1, &last_input_event), Qt); - if (CONSP (c) && EQ (XCAR (c), Qselect_window) && !end_time) + if (CONSP (c) + && (EQ (XCAR (c), Qselect_window) +#ifdef HAVE_DBUS + || EQ (XCAR (c), Qdbus_event) +#endif +#ifdef USE_FILE_NOTIFY + || EQ (XCAR (c), Qfile_notify) +#endif + || EQ (XCAR (c), Qconfig_changed_event)) + && !end_time) /* We stopped being idle for this event; undo that. This prevents automatic window selection (under - mouse_autoselect_window from acting as a real input event, for + mouse-autoselect-window) from acting as a real input event, for example banishing the mouse under mouse-avoidance-mode. */ timer_resume_idle (); @@ -3216,33 +3245,37 @@ record_char (Lisp_Object c) else store_kbd_macro_char (c); - if (!recorded) - { - total_keys += total_keys < NUM_RECENT_KEYS; - ASET (recent_keys, recent_keys_index, c); - if (++recent_keys_index >= NUM_RECENT_KEYS) - recent_keys_index = 0; - } - else if (recorded < 0) + /* recent_keys should not include events from keyboard macros. */ + if (NILP (Vexecuting_kbd_macro)) { - /* We need to remove one or two events from recent_keys. - To do this, we simply put nil at those events and move the - recent_keys_index backwards over those events. Usually, - users will never see those nil events, as they will be - overwritten by the command keys entered to see recent_keys - (e.g. C-h l). */ - - while (recorded++ < 0 && total_keys > 0) + if (!recorded) { - if (total_keys < NUM_RECENT_KEYS) - total_keys--; - if (--recent_keys_index < 0) - recent_keys_index = NUM_RECENT_KEYS - 1; - ASET (recent_keys, recent_keys_index, Qnil); + total_keys += total_keys < NUM_RECENT_KEYS; + ASET (recent_keys, recent_keys_index, c); + if (++recent_keys_index >= NUM_RECENT_KEYS) + recent_keys_index = 0; + } + else if (recorded < 0) + { + /* We need to remove one or two events from recent_keys. + To do this, we simply put nil at those events and move the + recent_keys_index backwards over those events. Usually, + users will never see those nil events, as they will be + overwritten by the command keys entered to see recent_keys + (e.g. C-h l). */ + + while (recorded++ < 0 && total_keys > 0) + { + if (total_keys < NUM_RECENT_KEYS) + total_keys--; + if (--recent_keys_index < 0) + recent_keys_index = NUM_RECENT_KEYS - 1; + ASET (recent_keys, recent_keys_index, Qnil); + } } - } - num_nonmacro_input_events++; + num_nonmacro_input_events++; + } /* Write c to the dribble file. If c is a lispy event, write the event's symbol to the dribble file, in . Bleaugh. @@ -3873,6 +3906,16 @@ kbd_buffer_get_event (KBOARD **kbp, kbd_fetch_ptr = event + 1; } #endif + +#ifdef HAVE_NTGUI + else if (event->kind == END_SESSION_EVENT) + { + /* Make an event (end-session). */ + obj = list1 (Qend_session); + kbd_fetch_ptr = event + 1; + } +#endif + #if defined (HAVE_X11) || defined (HAVE_NTGUI) \ || defined (HAVE_NS) else if (event->kind == ICONIFY_EVENT) @@ -4009,6 +4052,13 @@ kbd_buffer_get_event (KBOARD **kbp, obj = make_lispy_event (&event->ie); kbd_fetch_ptr = event + 1; } +#endif +#ifdef HAVE_XWIDGETS + else if (event->kind == XWIDGET_EVENT) + { + obj = make_lispy_event (&event->ie); + kbd_fetch_ptr = event + 1; + } #endif else if (event->kind == CONFIG_CHANGED_EVENT) { @@ -5946,12 +5996,19 @@ make_lispy_event (struct input_event *event) } #endif /* HAVE_DBUS */ -#if defined HAVE_GFILENOTIFY || defined HAVE_INOTIFY +#ifdef HAVE_XWIDGETS + case XWIDGET_EVENT: + { + return Fcons (Qxwidget_event, event->arg); + } +#endif + +#if defined HAVE_INOTIFY || defined HAVE_KQUEUE || defined HAVE_GFILENOTIFY case FILE_NOTIFY_EVENT: { return Fcons (Qfile_notify, event->arg); } -#endif /* defined HAVE_GFILENOTIFY || defined HAVE_INOTIFY */ +#endif /* HAVE_INOTIFY || HAVE_KQUEUE || HAVE_GFILENOTIFY */ case CONFIG_CHANGED_EVENT: return list3 (Qconfig_changed_event, @@ -6845,7 +6902,10 @@ tty_read_avail_input (struct terminal *terminal, the kbd_buffer can really hold. That may prevent loss of characters on some systems when input is stuffed at us. */ unsigned char cbuf[KBD_BUFFER_SIZE - 1]; - int n_to_read, i; +#ifndef WINDOWSNT + int n_to_read; +#endif + int i; struct tty_display_info *tty = terminal->display_info.tty; int nread = 0; #ifdef subprocesses @@ -8794,7 +8854,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, /* The length of the echo buffer when we started reading, and the length of this_command_keys when we started reading. */ - ptrdiff_t echo_start IF_LINT (= 0); + ptrdiff_t echo_start UNINIT; ptrdiff_t keys_start; Lisp_Object current_binding = Qnil; @@ -8842,7 +8902,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, While we're reading, we keep the event here. */ Lisp_Object delayed_switch_frame; - Lisp_Object original_uppercase IF_LINT (= Qnil); + Lisp_Object original_uppercase UNINIT; int original_uppercase_position = -1; /* Gets around Microsoft compiler limitations. */ @@ -8867,10 +8927,16 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, of echoing, so that it serves as a prompt for the next character. */ kset_echo_prompt (current_kboard, prompt); + /* FIXME: This use of echo_now doesn't look quite right and is ugly + since it forces us to fiddle with current_kboard->immediate_echo + before and after. */ current_kboard->immediate_echo = false; echo_now (); + if (!echo_keystrokes_p ()) + current_kboard->immediate_echo = false; } - else if (cursor_in_echo_area + else if (cursor_in_echo_area /* FIXME: Not sure why we test this here, + maybe we should just drop this test. */ && echo_keystrokes_p ()) /* 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. */ @@ -8946,7 +9012,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, while those allow us to restart the entire key sequence, echo_local_start and keys_local_start allow us to throw away just one key. */ - ptrdiff_t echo_local_start IF_LINT (= 0); + ptrdiff_t echo_local_start UNINIT; int keys_local_start; Lisp_Object new_binding; @@ -9846,7 +9912,7 @@ clear_input_pending (void) bool requeued_events_pending_p (void) { - return (!NILP (Vunread_command_events)); + return (CONSP (Vunread_command_events)); } DEFUN ("input-pending-p", Finput_pending_p, Sinput_pending_p, 0, 1, 0, @@ -9857,7 +9923,7 @@ if there is a doubt, the value is t. If CHECK-TIMERS is non-nil, timers that are ready to run will do so. */) (Lisp_Object check_timers) { - if (!NILP (Vunread_command_events) + if (CONSP (Vunread_command_events) || !NILP (Vunread_post_input_method_events) || !NILP (Vunread_input_method_events)) return (Qt); @@ -10199,6 +10265,21 @@ deliver_interrupt_signal (int sig) deliver_process_signal (sig, handle_interrupt_signal); } +/* Output MSG directly to standard output, without buffering. Ignore + failures. This is safe in a signal handler. */ +static void +write_stdout (char const *msg) +{ + ignore_value (write (STDOUT_FILENO, msg, strlen (msg))); +} + +/* Read a byte from stdin, without buffering. Safe in signal handlers. */ +static int +read_stdin (void) +{ + char c; + return read (STDIN_FILENO, &c, 1) == 1 ? c : EOF; +} /* If Emacs is stuck because `inhibit-quit' is true, then keep track of the number of times C-g has been requested. If C-g is pressed @@ -10235,9 +10316,9 @@ handle_interrupt (bool in_signal_handler) sigemptyset (&blocked); sigaddset (&blocked, SIGINT); pthread_sigmask (SIG_BLOCK, &blocked, 0); + fflush (stdout); } - fflush (stdout); reset_all_sys_modes (); #ifdef SIGTSTP @@ -10253,58 +10334,65 @@ handle_interrupt (bool in_signal_handler) /* Perhaps should really fork an inferior shell? But that would not provide any way to get back to the original shell, ever. */ - printf ("No support for stopping a process on this operating system;\n"); - printf ("you can continue or abort.\n"); + write_stdout ("No support for stopping a process" + " on this operating system;\n" + "you can continue or abort.\n"); #endif /* not SIGTSTP */ #ifdef MSDOS /* We must remain inside the screen area when the internal terminal is used. Note that [Enter] is not echoed by dos. */ cursor_to (SELECTED_FRAME (), 0, 0); #endif + + write_stdout ("Emacs is resuming after an emergency escape.\n"); + /* It doesn't work to autosave while GC is in progress; the code used for auto-saving doesn't cope with the mark bit. */ if (!gc_in_progress) { - printf ("Auto-save? (y or n) "); - fflush (stdout); - if (((c = getchar ()) & ~040) == 'Y') + write_stdout ("Auto-save? (y or n) "); + c = read_stdin (); + if (c == 'y' || c == 'Y') { Fdo_auto_save (Qt, Qnil); #ifdef MSDOS - printf ("\r\nAuto-save done"); -#else /* not MSDOS */ - printf ("Auto-save done\n"); -#endif /* not MSDOS */ + write_stdout ("\r\nAuto-save done"); +#else + write_stdout ("Auto-save done\n"); +#endif } - while (c != '\n') c = getchar (); + while (c != '\n') + c = read_stdin (); } else { /* During GC, it must be safe to reenable quitting again. */ Vinhibit_quit = Qnil; + write_stdout + ( #ifdef MSDOS - printf ("\r\n"); -#endif /* not MSDOS */ - printf ("Garbage collection in progress; cannot auto-save now\r\n"); - printf ("but will instead do a real quit after garbage collection ends\r\n"); - fflush (stdout); + "\r\n" +#endif + "Garbage collection in progress; cannot auto-save now\r\n" + "but will instead do a real quit" + " after garbage collection ends\r\n"); } #ifdef MSDOS - printf ("\r\nAbort? (y or n) "); -#else /* not MSDOS */ - printf ("Abort (and dump core)? (y or n) "); -#endif /* not MSDOS */ - fflush (stdout); - if (((c = getchar ()) & ~040) == 'Y') + write_stdout ("\r\nAbort? (y or n) "); +#else + write_stdout ("Abort (and dump core)? (y or n) "); +#endif + c = read_stdin (); + if (c == 'y' || c == 'Y') emacs_abort (); - while (c != '\n') c = getchar (); + while (c != '\n') + c = read_stdin (); #ifdef MSDOS - printf ("\r\nContinuing...\r\n"); + write_stdout ("\r\nContinuing...\r\n"); #else /* not MSDOS */ - printf ("Continuing...\n"); + write_stdout ("Continuing...\n"); #endif /* not MSDOS */ - fflush (stdout); init_all_sys_modes (); } else @@ -10905,6 +10993,8 @@ syms_of_keyboard (void) DEFSYM (Qpost_command_hook, "post-command-hook"); DEFSYM (Qundo_auto__add_boundary, "undo-auto--add-boundary"); + DEFSYM (Qundo_auto__undoably_changed_buffers, + "undo-auto--undoably-changed-buffers"); DEFSYM (Qdeferred_action_function, "deferred-action-function"); DEFSYM (Qdelayed_warnings_hook, "delayed-warnings-hook"); @@ -10922,12 +11012,17 @@ syms_of_keyboard (void) #ifdef HAVE_NTGUI DEFSYM (Qlanguage_change, "language-change"); + DEFSYM (Qend_session, "end-session"); #endif #ifdef HAVE_DBUS DEFSYM (Qdbus_event, "dbus-event"); #endif +#ifdef HAVE_XWIDGETS + DEFSYM (Qxwidget_event, "xwidget-event"); +#endif + #ifdef USE_FILE_NOTIFY DEFSYM (Qfile_notify, "file-notify"); #endif /* USE_FILE_NOTIFY */ @@ -11327,7 +11422,7 @@ See Info node `(elisp)Multiple Terminals'. */); DEFVAR_BOOL ("cannot-suspend", cannot_suspend, doc: /* Non-nil means to always spawn a subshell instead of suspending. -(Even if the operating system has support for stopping a process.) */); +\(Even if the operating system has support for stopping a process.) */); cannot_suspend = false; DEFVAR_BOOL ("menu-prompting", menu_prompting, @@ -11541,7 +11636,7 @@ immediately after running `post-command-hook'. */); DEFVAR_LISP ("input-method-function", Vinput_method_function, doc: /* If non-nil, the function that implements the current input method. It's called with one argument, a printing character that was just read. -(That means a character with code 040...0176.) +\(That means a character with code 040...0176.) Typically this function uses `read-event' to read additional events. When it does so, it should first bind `input-method-function' to nil so it will not be called recursively. @@ -11574,10 +11669,10 @@ It's called with one argument, the help string to display. */); DEFVAR_LISP ("disable-point-adjustment", Vdisable_point_adjustment, doc: /* If non-nil, suppress point adjustment after executing a command. -After a command is executed, if point is moved into a region that has -special properties (e.g. composition, display), we adjust point to -the boundary of the region. But, when a command sets this variable to -non-nil, we suppress the point adjustment. +After a command is executed, if point moved into a region that has +special properties (e.g. composition, display), Emacs adjusts point to +the boundary of the region. But when a command leaves this variable at +a non-nil value (e.g., with a setq), this point adjustment is suppressed. This variable is set to nil before reading a command, and is checked just after executing the command. */); @@ -11585,11 +11680,11 @@ just after executing the command. */); DEFVAR_LISP ("global-disable-point-adjustment", Vglobal_disable_point_adjustment, - doc: /* If non-nil, always suppress point adjustment. + doc: /* If non-nil, always suppress point adjustments. -The default value is nil, in which case, point adjustment are -suppressed only after special commands that set -`disable-point-adjustment' (which see) to non-nil. */); +The default value is nil, in which case point adjustments are +suppressed only after special commands that leave +`disable-point-adjustment' (which see) at a non-nil value. */); Vglobal_disable_point_adjustment = Qnil; DEFVAR_LISP ("minibuffer-message-timeout", Vminibuffer_message_timeout, @@ -11658,6 +11753,25 @@ Currently, the only supported values for this variable are `sigusr1' and `sigusr2'. */); Vdebug_on_event = intern_c_string ("sigusr2"); + DEFVAR_BOOL ("attempt-stack-overflow-recovery", + attempt_stack_overflow_recovery, + doc: /* If non-nil, attempt to recover from C stack +overflow. This recovery is unsafe and may lead to deadlocks or data +corruption, but it usually works and may preserve modified buffers +that would otherwise be lost. If nil, treat stack overflow like any +other kind of crash. */); + attempt_stack_overflow_recovery = true; + + DEFVAR_BOOL ("attempt-orderly-shutdown-on-fatal-signal", + attempt_orderly_shutdown_on_fatal_signal, + doc: /* If non-nil, attempt to perform an orderly +shutdown when Emacs receives a fatal signal (e.g., a crash). +This cleanup is unsafe and may lead to deadlocks or data corruption, +but it usually works and may preserve modified buffers that would +otherwise be lost. If nil, crash immediately in response to fatal +signals. */); + attempt_orderly_shutdown_on_fatal_signal = true; + /* Create the initial keyboard. Qt means 'unset'. */ initial_kboard = allocate_kboard (Qt); } @@ -11673,6 +11787,10 @@ keys_of_keyboard (void) initial_define_lispy_key (Vspecial_event_map, "delete-frame", "handle-delete-frame"); +#ifdef HAVE_NTGUI + initial_define_lispy_key (Vspecial_event_map, "end-session", + "kill-emacs"); +#endif initial_define_lispy_key (Vspecial_event_map, "ns-put-working-text", "ns-put-working-text"); initial_define_lispy_key (Vspecial_event_map, "ns-unput-working-text",