/* Keyboard and mouse input; editor command loop.
- Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99,2000,01,02,03
+ Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99,2000,01,02,03,04
Free Software Foundation, Inc.
This file is part of GNU Emacs.
static struct input_event kbd_buffer[KBD_BUFFER_SIZE];
-/* 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,
- internal_last_event_frame or the event itself points to the frame.
- So that's all fine.
-
- But while the event is sitting in the queue, it's completely
- unprotected. Suppose the user types one command which will run for
- a while and then delete a frame, and then types another event at
- the frame that will be deleted, before the command gets around to
- it. Suppose there are no references to this frame elsewhere in
- Emacs, and a GC occurs before the second event is dequeued. Now we
- have an event referring to a freed frame, which will crash Emacs
- when it is dequeued.
-
- 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 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
-
- 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.
This may be kbd_buffer + KBD_BUFFER_SIZE, meaning that the
static void clear_event P_ ((struct input_event *));
static void any_kboard_state P_ ((void));
static SIGTYPE interrupt_signal P_ ((int signalnum));
+static void handle_interrupt P_ ((void));
/* Nonzero means don't try to suspend even if the operating system seems
to support it. */
if (!sf->glyphs_initialized_p
/* This is the case of the frame dumped with Emacs, when we're
running under a window system. */
- || (!NILP (Vwindow_system)
- && !inhibit_window_system
- && FRAME_TERMCAP_P (sf)
- && !FRAME_TTY (sf)->type) /* XXX This is ugly. */
+ || FRAME_INITIAL_P (sf)
|| noninteractive)
{
stream = Qexternal_debugging_output;
{
Lisp_Object posn;
- posn = POSN_BUFFER_POSN (EVENT_START (c));
+ posn = POSN_POSN (EVENT_START (c));
/* Handle menu-bar events:
insert the dummy prefix event `menu-bar'. */
if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar))
{
/* Change menu-bar to (menu-bar) as the event "position". */
- POSN_BUFFER_SET_POSN (EVENT_START (c), Fcons (posn, Qnil));
+ POSN_SET_POSN (EVENT_START (c), Fcons (posn, Qnil));
also_record = c;
Vunread_command_events = Fcons (c, Vunread_command_events);
}
last_event_timestamp = event->timestamp;
- interrupt_signal (0 /* dummy */);
+ handle_interrupt ();
return;
}
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
*kbd_store_ptr = *event;
#endif
- 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;
}
}
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;
}
{
/* It's a click in window window at frame coordinates (x,y) */
struct window *w = XWINDOW (window);
- Lisp_Object object = Qnil;
+ Lisp_Object string_info = Qnil;
int textpos = -1, rx = -1, ry = -1;
int dx = -1, dy = -1;
+ int width = -1, height = -1;
+ Lisp_Object object = Qnil;
/* Set event coordinates to window-relative coordinates
for constructing the Lisp event below. */
posn = part == ON_MODE_LINE ? Qmode_line : Qheader_line;
rx = wx, ry = wy;
- string = mode_line_string (w, &rx, &ry, &dx, &dy, part, &charpos);
+ string = mode_line_string (w, part, &rx, &ry, &charpos,
+ &object, &dx, &dy, &width, &height);
if (STRINGP (string))
- object = Fcons (string, make_number (charpos));
+ string_info = Fcons (string, make_number (charpos));
if (w == XWINDOW (selected_window))
textpos = PT;
else
posn = Qvertical_line;
wx = -1;
dx = 0;
+ width = 1;
}
else if (part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN)
{
posn = (part == ON_LEFT_MARGIN) ? Qleft_margin : Qright_margin;
rx = wx, ry = wy;
- string = marginal_area_string (w, &rx, &ry, &dx, &dy, part, &charpos);
+ string = marginal_area_string (w, part, &rx, &ry, &charpos,
+ &object, &dx, &dy, &width, &height);
if (STRINGP (string))
- object = Fcons (string, make_number (charpos));
-#ifdef HAVE_WINDOW_SYSTEM
- else if (IMAGEP (string))
- {
- Lisp_Object image_map, hotspot;
- object = string;
- if ((image_map = Fplist_get (XCDR (object), QCmap),
- !NILP (image_map))
- && (hotspot = find_hot_spot (image_map, dx, dy),
- CONSP (hotspot))
- && (hotspot = XCDR (hotspot), CONSP (hotspot)))
- posn = XCAR (hotspot);
- }
-#endif
+ string_info = Fcons (string, make_number (charpos));
}
else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE)
{
if (textpos < 0)
{
- Lisp_Object string;
+ Lisp_Object string2, object2 = Qnil;
struct display_pos p;
int dx2, dy2;
+ int width2, height2;
wx = max (WINDOW_LEFT_MARGIN_WIDTH (w), wx);
- buffer_posn_from_coords (w, &wx, &wy, &dx2, &dy2, &string, &p);
+ string2 = buffer_posn_from_coords (w, &wx, &wy, &p,
+ &object2, &dx2, &dy2,
+ &width2, &height2);
textpos = CHARPOS (p.pos);
if (rx < 0) rx = wx;
if (ry < 0) ry = wy;
if (dx < 0) dx = dx2;
if (dy < 0) dy = dy2;
+ if (width < 0) width = width2;
+ if (height < 0) height = height2;
if (NILP (posn))
{
posn = make_number (textpos);
- if (STRINGP (string))
- object = Fcons (string,
- make_number (CHARPOS (p.string_pos)));
-#ifdef HAVE_WINDOW_SYSTEM
- else if (IMAGEP (string))
- {
- Lisp_Object image_map, hotspot;
- object = string;
- if ((image_map = Fplist_get (XCDR (object), QCmap),
- !NILP (image_map))
- && (hotspot = find_hot_spot (image_map, dx, dy),
- CONSP (hotspot))
- && (hotspot = XCDR (hotspot), CONSP (hotspot)))
- posn = XCAR (hotspot);
- }
-#endif
+ if (STRINGP (string2))
+ string_info = Fcons (string2,
+ make_number (CHARPOS (p.string_pos)));
}
+ if (NILP (object))
+ object = object2;
}
+#ifdef HAVE_WINDOW_SYSTEM
+ if (IMAGEP (object))
+ {
+ Lisp_Object image_map, hotspot;
+ if ((image_map = Fplist_get (XCDR (object), QCmap),
+ !NILP (image_map))
+ && (hotspot = find_hot_spot (image_map, dx, dy),
+ CONSP (hotspot))
+ && (hotspot = XCDR (hotspot), CONSP (hotspot)))
+ posn = XCAR (hotspot);
+ }
+#endif
+
+ /* Object info */
extra_info = Fcons (object,
+ Fcons (Fcons (make_number (dx),
+ make_number (dy)),
+ Fcons (Fcons (make_number (width),
+ make_number (height)),
+ Qnil)));
+
+ /* String info */
+ extra_info = Fcons (string_info,
Fcons (make_number (textpos),
Fcons (Fcons (make_number (rx),
make_number (ry)),
- Fcons (Fcons (make_number (dx),
- make_number (dy)),
- Qnil))));
+ extra_info)));
}
else if (f != 0)
{
{
struct input_event buf[KBD_BUFFER_SIZE];
register int i;
+ struct display *d;
int nread = 0;
for (i = 0; i < KBD_BUFFER_SIZE; i++)
EVENT_INIT (buf[i]);
- {
- struct display *d;
+ d = display_list;
+ while (d)
+ {
+ struct display *next = d->next_display;
+
+ if (d->read_socket_hook)
+ /* No need for FIONREAD or fcntl; just say don't wait. */
+ nread = (*d->read_socket_hook) (d, buf, KBD_BUFFER_SIZE, expected);
- for (d = display_list; d; d = d->next_display)
- {
- if (d->read_socket_hook)
- /* No need for FIONREAD or fcntl; just say don't wait. */
- nread = (*d->read_socket_hook) (buf, KBD_BUFFER_SIZE, expected);
-
- if (nread > 0)
+ if (nread == -2)
+ {
+ /* The display device terminated; it should be closed. */
+
+ /* Kill Emacs if this was our last display. */
+ if (! display_list->next_display)
+ kill (getpid (), SIGHUP);
+
+ /* XXX Is calling delete_display safe here? It calls Fdelete_frame. */
+ if (d->delete_display_hook)
+ (*d->delete_display_hook) (d);
+ else
+ delete_display (d);
+ }
+ else if (nread > 0)
+ {
+ /* We've got input. */
break;
- }
- }
+ }
+
+ d = next;
+ }
- if (nread <= 0 && tty_list)
+ /* Scan the chars for C-g and store them in kbd_buffer. */
+ for (i = 0; i < nread; i++)
{
- /* Using KBD_BUFFER_SIZE - 1 here avoids reading more than
- 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;
- struct tty_display_info *tty;
- Lisp_Object frame;
-
-#ifdef WINDOWSNT
- return 0;
-#else /* not WINDOWSNT */
-#ifdef MSDOS
- n_to_read = dos_keysns ();
- if (n_to_read == 0)
- return 0;
+ kbd_buffer_store_event (&buf[i]);
+ /* Don't look at input that follows a C-g too closely.
+ This reduces lossage due to autorepeat on C-g. */
+ if (buf[i].kind == ASCII_KEYSTROKE_EVENT
+ && buf[i].code == quit_char)
+ break;
+ }
- cbuf[0] = dos_keyread ();
- nread = 1;
+ return nread;
+}
-#else /* not MSDOS */
+/* This is the tty way of reading available input.
- nread = 0;
+ Note that each terminal device has its own `struct display' object,
+ and so this function is called once for each individual termcap
+ display. The first parameter indicates which device to read from. */
- /* Try to read from each available tty, until one succeeds. */
- for (tty = tty_list; tty; tty = tty->next) {
+int
+tty_read_avail_input (struct display *display,
+ struct input_event *buf,
+ int numchars, int expected)
+{
+ /* Using KBD_BUFFER_SIZE - 1 here avoids reading more than
+ 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;
+ struct tty_display_info *tty = display->display_info.tty;
+ Lisp_Object frame;
+ int nread = 0;
+
+ if (display->type != output_termcap)
+ abort ();
+
+ /* XXX I think the following code should be moved to separate
+ functions in system-dependent files. */
+#ifdef WINDOWSNT
+ return 0;
+#else /* not WINDOWSNT */
+#ifdef MSDOS
+ n_to_read = dos_keysns ();
+ if (n_to_read == 0)
+ return 0;
+
+ cbuf[0] = dos_keyread ();
+ nread = 1;
+
+#else /* not MSDOS */
- if (! tty->term_initted)
- continue;
+ if (! tty->term_initted)
+ return 0;
- /* Determine how many characters we should *try* to read. */
+ /* Determine how many characters we should *try* to read. */
#ifdef FIONREAD
- /* Find out how much input is available. */
- if (ioctl (fileno (TTY_INPUT (tty)), FIONREAD, &n_to_read) < 0)
- {
- /* Formerly simply reported no input, but that sometimes led to
- a failure of Emacs to terminate.
- SIGHUP seems appropriate if we can't reach the terminal. */
- /* ??? Is it really right to send the signal just to this process
- rather than to the whole process group?
- Perhaps on systems with FIONREAD Emacs is alone in its group. */
- /* It appears to be the case, see narrow_foreground_group. */
- if (! noninteractive)
- {
- if (! tty_list->next)
- kill (getpid (), SIGHUP); /* This was the last terminal. */
- else
- n_to_read = 0; /* XXX tty should be closed here. */
- }
- else
- {
- n_to_read = 0;
- }
- }
- if (n_to_read == 0)
- continue;
- if (n_to_read > sizeof cbuf)
- n_to_read = sizeof cbuf;
+ /* Find out how much input is available. */
+ if (ioctl (fileno (TTY_INPUT (tty)), FIONREAD, &n_to_read) < 0)
+ {
+ if (! noninteractive)
+ return -2; /* Close this display. */
+ else
+ n_to_read = 0;
+ }
+ if (n_to_read == 0)
+ return 0;
+ if (n_to_read > sizeof cbuf)
+ n_to_read = sizeof cbuf;
#else /* no FIONREAD */
#if defined (USG) || defined (DGUX) || defined(CYGWIN)
- /* Read some input if available, but don't wait. */
- n_to_read = sizeof cbuf;
- fcntl (fileno (TTY_INPUT (tty)), F_SETFL, O_NDELAY);
+ /* Read some input if available, but don't wait. */
+ n_to_read = sizeof cbuf;
+ fcntl (fileno (TTY_INPUT (tty)), F_SETFL, O_NDELAY);
#else
- you lose;
+ you lose;
#endif
#endif
-
- /* Now read; for one reason or another, this will not block.
- NREAD is set to the number of chars read. */
- do
- {
- nread = emacs_read (fileno (TTY_INPUT (tty)), cbuf, n_to_read);
- /* POSIX infers that processes which are not in the session leader's
- process group won't get SIGHUP's at logout time. BSDI adheres to
- this part standard and returns -1 from read (0) with errno==EIO
- when the control tty is taken away.
- Jeffrey Honig <jch@bsdi.com> says this is generally safe. */
- if (nread == -1 && errno == EIO)
- {
- if (! tty_list->next)
- kill (0, SIGHUP); /* This was the last terminal. */
- else
- delete_tty (tty); /* XXX I wonder if this is safe here. */
- }
+
+ /* Now read; for one reason or another, this will not block.
+ NREAD is set to the number of chars read. */
+ do
+ {
+ nread = emacs_read (fileno (TTY_INPUT (tty)), cbuf, n_to_read);
+ /* POSIX infers that processes which are not in the session leader's
+ process group won't get SIGHUP's at logout time. BSDI adheres to
+ this part standard and returns -1 from read (0) with errno==EIO
+ when the control tty is taken away.
+ Jeffrey Honig <jch@bsdi.com> says this is generally safe. */
+ if (nread == -1 && errno == EIO)
+ {
+ return -2; /* Close this display. */
+ }
#if defined (AIX) && (! defined (aix386) && defined (_BSD))
- /* The kernel sometimes fails to deliver SIGHUP for ptys.
- This looks incorrect, but it isn't, because _BSD causes
- O_NDELAY to be defined in fcntl.h as O_NONBLOCK,
- and that causes a value other than 0 when there is no input. */
- if (nread == 0)
- {
- if (! tty_list->next)
- kill (0, SIGHUP); /* This was the last terminal. */
- else
- delete_tty (tty); /* XXX I wonder if this is safe here. */
- }
+ /* The kernel sometimes fails to deliver SIGHUP for ptys.
+ This looks incorrect, but it isn't, because _BSD causes
+ O_NDELAY to be defined in fcntl.h as O_NONBLOCK,
+ and that causes a value other than 0 when there is no input. */
+ if (nread == 0)
+ {
+ return -2; /* Close this display. */
+ }
#endif
- }
- while (
- /* We used to retry the read if it was interrupted.
- But this does the wrong thing when O_NDELAY causes
- an EAGAIN error. Does anybody know of a situation
- where a retry is actually needed? */
+ }
+ while (
+ /* We used to retry the read if it was interrupted.
+ But this does the wrong thing when O_NDELAY causes
+ an EAGAIN error. Does anybody know of a situation
+ where a retry is actually needed? */
#if 0
- nread < 0 && (errno == EAGAIN
+ nread < 0 && (errno == EAGAIN
#ifdef EFAULT
- || errno == EFAULT
+ || errno == EFAULT
#endif
#ifdef EBADSLT
- || errno == EBADSLT
+ || errno == EBADSLT
#endif
- )
+ )
#else
- 0
+ 0
#endif
- );
-
+ );
+
#ifndef FIONREAD
#if defined (USG) || defined (DGUX) || defined (CYGWIN)
- fcntl (fileno (TTY_INPUT (tty)), F_SETFL, 0);
+ fcntl (fileno (TTY_INPUT (tty)), F_SETFL, 0);
#endif /* USG or DGUX or CYGWIN */
#endif /* no FIONREAD */
-
- if (nread > 0)
- break;
- } /* for each tty */
-
- if (nread <= 0)
- return 0;
-
+
+ if (nread <= 0)
+ return nread;
+
#endif /* not MSDOS */
#endif /* not WINDOWSNT */
-
- if (!tty)
- abort ();
-
- /* Select frame corresponding to the active tty. Note that the
- value of selected_frame is not reliable here, redisplay tends
- to temporarily change it. But tty should always be non-NULL. */
- frame = tty->top_frame;
-
- for (i = 0; i < nread; i++)
- {
- buf[i].kind = ASCII_KEYSTROKE_EVENT;
- buf[i].modifiers = 0;
- if (tty->meta_key == 1 && (cbuf[i] & 0x80))
- buf[i].modifiers = meta_modifier;
- if (tty->meta_key != 2)
- cbuf[i] &= ~0x80;
-
- buf[i].code = cbuf[i];
- buf[i].frame_or_window = frame;
- buf[i].arg = Qnil;
- }
- }
-
- /* Scan the chars for C-g and store them in kbd_buffer. */
+
+ /* Select the frame corresponding to the active tty. Note that the
+ value of selected_frame is not reliable here, redisplay tends to
+ temporarily change it. */
+ frame = tty->top_frame;
+
for (i = 0; i < nread; i++)
{
- kbd_buffer_store_event (&buf[i]);
- /* Don't look at input that follows a C-g too closely.
- This reduces lossage due to autorepeat on C-g. */
- if (buf[i].kind == ASCII_KEYSTROKE_EVENT
- && buf[i].code == quit_char)
- break;
+ buf[i].kind = ASCII_KEYSTROKE_EVENT;
+ buf[i].modifiers = 0;
+ if (tty->meta_key == 1 && (cbuf[i] & 0x80))
+ buf[i].modifiers = meta_modifier;
+ if (tty->meta_key != 2)
+ cbuf[i] &= ~0x80;
+
+ buf[i].code = cbuf[i];
+ buf[i].frame_or_window = frame;
+ buf[i].arg = Qnil;
}
return nread;
}
+
#endif /* not VMS */
\f
+void
+handle_async_input ()
+{
+#ifdef BSD4_1
+ extern int select_alarmed;
+#endif
+ interrupt_input_pending = 0;
+
+ while (1)
+ {
+ int nread;
+ nread = read_avail_input (1);
+ /* -1 means it's not ok to read the input now.
+ UNBLOCK_INPUT will read it later; now, avoid infinite loop.
+ 0 means there was no keyboard input available. */
+ if (nread <= 0)
+ break;
+
+#ifdef BSD4_1
+ select_alarmed = 1; /* Force the select emulator back to life */
+#endif
+ }
+}
+
#ifdef SIGIO /* for entire page */
/* Note SIGIO has been undef'd if FIONREAD is missing. */
{
/* Must preserve main program's value of errno. */
int old_errno = errno;
-#ifdef BSD4_1
- extern int select_alarmed;
-#endif
#if defined (USG) && !defined (POSIX_SIGNALS)
/* USG systems forget handlers when they are used;
if (input_available_clear_time)
EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0);
- while (1)
- {
- int nread;
- nread = read_avail_input (1);
- /* -1 means it's not ok to read the input now.
- UNBLOCK_INPUT will read it later; now, avoid infinite loop.
- 0 means there was no keyboard input available. */
- if (nread <= 0)
- break;
-
-#ifdef BSD4_1
- select_alarmed = 1; /* Force the select emulator back to life */
+#ifdef SYNC_INPUT
+ interrupt_input_pending = 1;
+#else
+ handle_async_input ();
#endif
- }
#ifdef BSD4_1
sigfree ();
reinvoke_input_signal ()
{
#ifdef SIGIO
- kill (getpid (), SIGIO);
+ handle_async_input ();
#endif
}
Lisp_Object window, posn;
window = POSN_WINDOW (EVENT_START (key));
- posn = POSN_BUFFER_POSN (EVENT_START (key));
+ posn = POSN_POSN (EVENT_START (key));
if (CONSP (posn)
|| (!NILP (fake_prefixed_keys)
localized_local_map = 1;
start = EVENT_START (key);
- if (CONSP (start) && CONSP (XCDR (start)))
+ if (CONSP (start) && POSN_INBUFFER_P (start))
{
pos = POSN_BUFFER_POSN (start);
if (INTEGERP (pos)
{
Lisp_Object posn;
- posn = POSN_BUFFER_POSN (EVENT_START (key));
+ posn = POSN_POSN (EVENT_START (key));
/* Handle menu-bar events:
insert the dummy prefix event `menu-bar'. */
if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar))
/* Zap the position in key, so we know that we've
expanded it, and don't try to do so again. */
- POSN_BUFFER_SET_POSN (EVENT_START (key),
- Fcons (posn, Qnil));
+ POSN_SET_POSN (EVENT_START (key),
+ Fcons (posn, Qnil));
mock_input = t + 2;
goto replay_sequence;
discard_tty_input ();
kbd_fetch_ptr = kbd_store_ptr;
- Ffillarray (kbd_buffer_gcpro, Qnil);
input_pending = 0;
return Qnil;
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_EVENT)
stuff_char (kbd_fetch_ptr->code);
- kbd_fetch_ptr->kind = NO_EVENT;
- idx = 2 * (kbd_fetch_ptr - kbd_buffer);
- ASET (kbd_buffer_gcpro, idx, Qnil);
- ASET (kbd_buffer_gcpro, idx + 1, Qnil);
+ clear_event (kbd_fetch_ptr);
}
input_pending = 0;
{
input_available_clear_time = time_to_clear;
- /* Tell interrupt_signal to throw back to read_char, */
+ /* Tell handle_interrupt to throw back to read_char, */
waiting_for_input = 1;
- /* If interrupt_signal was called before and buffered a C-g,
+ /* If handle_interrupt was called before and buffered a C-g,
make it run again now, to avoid timing error. */
if (!NILP (Vquit_flag))
quit_throw_to_read_char ();
void
clear_waiting_for_input ()
{
- /* Tell interrupt_signal not to throw back to read_char, */
+ /* Tell handle_interrupt not to throw back to read_char, */
waiting_for_input = 0;
input_available_clear_time = 0;
}
-/* 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 `waiting_for_input' is non zero, then unless `echoing' is
- nonzero, immediately throw back to read_char.
+/* The SIGINT handler.
- 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. */
+ If we have a frame on the controlling tty, the SIGINT was generated
+ by C-g, so we call handle_interrupt. Otherwise, the handler kills
+ Emacs. */
static SIGTYPE
interrupt_signal (signalnum) /* If we don't have an argument, */
int signalnum; /* some compilers complain in signal calls. */
{
- char c;
/* Must preserve main program's value of errno. */
int old_errno = errno;
- struct frame *sf = SELECTED_FRAME ();
+ struct display *display;
#if defined (USG) && !defined (POSIX_SIGNALS)
/* USG systems forget handlers when they are used;
signal (SIGQUIT, interrupt_signal);
#endif /* USG */
+ /* See if we have a display on our controlling terminal. */
+ display = get_named_tty_display (NULL);
+ if (!display)
+ {
+ /* If there are no frames there, let's pretend that we are a
+ well-behaving UN*X program and quit. */
+ Fkill_emacs (Qnil);
+ }
+ else
+ {
+ /* Otherwise, the SIGINT was probably generated by C-g. */
+
+ /* Set internal_last_event_frame to the top frame of the
+ controlling tty, if we have a frame there. We disable the
+ interrupt key on secondary ttys, so the SIGINT must have come
+ from the controlling tty. */
+ internal_last_event_frame = display->display_info.tty->top_frame;
+
+ handle_interrupt ();
+ }
+
+ errno = old_errno;
+}
+
+/* This routine is called at interrupt level in response to C-g.
+
+ It is called from the SIGINT handler or kbd_buffer_store_event.
+
+ 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. */
+
+static void
+handle_interrupt ()
+{
+ char c;
+ struct frame *sf = SELECTED_FRAME ();
+
cancel_echoing ();
+ /* XXX This code needs to be revised for multi-tty support. */
if (!NILP (Vquit_flag)
&& (FRAME_TERMCAP_P (sf) || FRAME_MSDOS_P (sf)))
{
}
if (waiting_for_input && !echoing)
- quit_throw_to_read_char ();
-
- errno = old_errno;
+ quit_throw_to_read_char ();
}
/* Handle a C-g by making read_char return C-g. */
#ifndef DOS_NT
/* this causes startup screen to be restored and messes with the mouse */
- if (FRAME_TERMCAP_P (SELECTED_FRAME ()) && CURTTY ()->type)
- reset_sys_modes (CURTTY ());
+ reset_all_sys_modes ();
#endif
#ifdef SIGIO
if (!NILP (quit))
/* Don't let this value be out of range. */
- quit_char = XINT (quit) & (CURTTY ()->meta_key ? 0377 : 0177);
+ quit_char = XINT (quit) & (NILP (meta) ? 0177 : 0377);
#ifndef DOS_NT
- if (FRAME_TERMCAP_P (XFRAME (selected_frame)) && CURTTY ()->type)
- init_sys_modes (CURTTY ());
+ init_all_sys_modes ();
#endif
#ifdef POLL_FOR_INPUT
recent_keys_index = 0;
kbd_fetch_ptr = kbd_buffer;
kbd_store_ptr = kbd_buffer;
- kbd_buffer_gcpro = Fmake_vector (make_number (2 * KBD_BUFFER_SIZE), Qnil);
#ifdef HAVE_MOUSE
do_mouse_tracking = Qnil;
#endif
if (!noninteractive)
{
+ /* Before multi-tty support, these handlers used to be installed
+ only if the current session was a tty session. Now an Emacs
+ session may have multiple display types, so we always handle
+ SIGINT. There is special code in interrupt_signal to exit
+ Emacs on SIGINT when there are no termcap frames on the
+ controlling terminal. */
signal (SIGINT, interrupt_signal);
#if defined (HAVE_TERMIO) || defined (HAVE_TERMIOS)
/* For systems with SysV TERMIO, C-g is set up for both SIGINT and
Fset (Qextended_command_history, Qnil);
staticpro (&Qextended_command_history);
- kbd_buffer_gcpro = Fmake_vector (make_number (2 * KBD_BUFFER_SIZE), Qnil);
- staticpro (&kbd_buffer_gcpro);
-
accent_key_syms = Qnil;
staticpro (&accent_key_syms);