/* 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.
#include <unistd.h>
#include <fcntl.h>
+#include <ignore-value.h>
+
#ifdef HAVE_WINDOW_SYSTEM
#include TERM_HEADER
#endif /* HAVE_WINDOW_SYSTEM */
/* 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. */
static EMACS_INT last_auto_save;
-/* The value of point when the last command was started. */
+/* The value of point when the last command was started. */
static ptrdiff_t last_point_position;
/* The frame in which the last input event occurred, or Qmacro if the
bool, bool, bool, bool);
static void adjust_point_for_property (ptrdiff_t, bool);
-/* The last boundary auto-added to buffer-undo-list. */
-Lisp_Object last_undo_boundary;
-
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;
while (1)
{
+ Lisp_Object cmd;
+ Lisp_Object keybuf[30];
+ int i;
+
if (! FRAME_LIVE_P (XFRAME (selected_frame)))
Fkill_emacs (Qnil);
}
#endif
- {
- Lisp_Object undo = BVAR (current_buffer, undo_list);
- Fundo_boundary ();
- last_undo_boundary
- = (EQ (undo, BVAR (current_buffer, undo_list))
- ? Qnil : BVAR (current_buffer, undo_list));
- }
+ /* Ensure that we have added appropriate undo-boundaries as a
+ result of changes from the last command. */
+ call0 (Qundo_auto__add_boundary);
+
+ /* Record point and buffer, so we can put point into the undo
+ information if necessary. */
+ point_before_last_command_or_undo = PT;
+ buffer_before_last_command_or_undo = current_buffer;
+
call1 (Qcommand_execute, Vthis_command);
#ifdef HAVE_WINDOW_SYSTEM
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 <brackets>. Bleaugh.
#endif
))
{
- union buffered_input_event *event;
-
- event = ((kbd_fetch_ptr < kbd_buffer + KBD_BUFFER_SIZE)
- ? kbd_fetch_ptr
- : kbd_buffer);
+ union buffered_input_event *event = kbd_fetch_ptr;
do
{
+ if (event == kbd_buffer + KBD_BUFFER_SIZE)
+ event = kbd_buffer;
if (!(
#ifdef USE_TOOLKIT_SCROLL_BARS
(flags & READABLE_EVENTS_FILTER_EVENTS) &&
&& event->kind == BUFFER_SWITCH_EVENT))
return 1;
event++;
- if (event == kbd_buffer + KBD_BUFFER_SIZE)
- event = kbd_buffer;
}
while (event != kbd_store_ptr);
}
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)
{
}
#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,
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
sigemptyset (&blocked);
sigaddset (&blocked, SIGINT);
pthread_sigmask (SIG_BLOCK, &blocked, 0);
+ fflush (stdout);
}
- fflush (stdout);
reset_all_sys_modes ();
#ifdef SIGTSTP
/* 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
DEFSYM (Qpre_command_hook, "pre-command-hook");
DEFSYM (Qpost_command_hook, "post-command-hook");
+ DEFSYM (Qundo_auto__add_boundary, "undo-auto--add-boundary");
+
DEFSYM (Qdeferred_action_function, "deferred-action-function");
DEFSYM (Qdelayed_warnings_hook, "delayed-warnings-hook");
DEFSYM (Qfunction_key, "function-key");
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 */
the function in which the error occurred is unconditionally removed, since
otherwise the error might happen repeatedly and make Emacs nonfunctional.
-See also `pre-command-hook'. */);
+See also `post-command-hook'. */);
Vpre_command_hook = Qnil;
DEFVAR_LISP ("post-command-hook", Vpost_command_hook,
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 binds this variable to
+non-nil, this point adjustment is suppressed.
This variable is set to nil before reading a command, and is checked
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
+The default value is nil, in which case point adjustments are
suppressed only after special commands that set
`disable-point-adjustment' (which see) to non-nil. */);
Vglobal_disable_point_adjustment = Qnil;
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);
}