#include <config.h>
#include <signal.h>
#include <stdio.h>
+#include "lisp.h"
#include "termchar.h"
#include "termopts.h"
-#include "lisp.h"
+#include "frame.h"
#include "termhooks.h"
#include "macros.h"
#include "keyboard.h"
-#include "frame.h"
#include "window.h"
#include "commands.h"
#include "buffer.h"
#endif /* not MSDOS */
#include "syssignal.h"
-#include "systty.h"
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
int interrupt_input_pending;
-/* File descriptor to use for input. */
-extern int input_fd;
-
#ifdef HAVE_WINDOW_SYSTEM
/* Make all keyboard buffers much bigger when using X windows. */
#ifdef MAC_OS8
/* Nonzero if input is available. */
int input_pending;
-/* 1 if should obey 0200 bit in input chars as "Meta", 2 if should
- keep 0200 bit in input chars. 0 to ignore the 0200 bit. */
-
-int meta_key;
-
/* Non-zero means force key bindings update in parse_menu_item. */
int update_menu_bindings;
/* Nonzero while interrupts are temporarily deferred during redisplay. */
int interrupts_deferred;
-/* Nonzero means use ^S/^Q for flow control. */
-int flow_control;
-
/* Allow m- file to inhibit use of FIONREAD. */
#ifdef BROKEN_FIONREAD
#undef FIONREAD
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_INITIAL_P (sf)
|| noninteractive)
{
stream = Qexternal_debugging_output;
start_polling ()
{
#ifdef POLL_FOR_INPUT
- if (read_socket_hook && !interrupt_input)
+ /* XXX This condition was (read_socket_hook && !interrupt_input),
+ but read_socket_hook is not global anymore. Let's pretend that
+ it's always set. */
+ if (!interrupt_input)
{
/* Turn alarm handling on unconditionally. It might have
been turned off in process.c. */
input_polling_used ()
{
#ifdef POLL_FOR_INPUT
- return read_socket_hook && !interrupt_input;
+ /* XXX This condition was (read_socket_hook && !interrupt_input),
+ but read_socket_hook is not global anymore. Let's pretend that
+ it's always set. */
+ return !interrupt_input;
#else
return 0;
#endif
stop_polling ()
{
#ifdef POLL_FOR_INPUT
- if (read_socket_hook && !interrupt_input)
+ /* XXX This condition was (read_socket_hook && !interrupt_input),
+ but read_socket_hook is not global anymore. Let's pretend that
+ it's always set. */
+ if (!interrupt_input)
++poll_suppress_count;
#endif
}
}
last_event_timestamp = event->timestamp;
- interrupt_signal (0 /* dummy */);
+ handle_interrupt ();
return;
}
If there is no valid info, it does not store anything
so x remains nil. */
x = Qnil;
- (*mouse_position_hook) (&f, 0, &bar_window, &part, &x, &y, &time);
+ if (f && FRAME_DISPLAY (f)->mouse_position_hook) /* XXX Can f or mouse_position_hook be NULL here? */
+ (*FRAME_DISPLAY (f)->mouse_position_hook) (&f, 0, &bar_window, &part, &x, &y, &time);
obj = Qnil;
/* If input is being read as it arrives, and we have none, there is none. */
if (*addr > 0 || (interrupt_input && ! interrupts_deferred))
return;
-
+
/* Try to read some input and see how much we get. */
gobble_input (0);
*addr = (!NILP (Vquit_flag)
}
else
#ifdef POLL_FOR_INPUT
- if (read_socket_hook && !interrupt_input && poll_suppress_count == 0)
+ /* XXX This condition was (read_socket_hook && !interrupt_input),
+ but read_socket_hook is not global anymore. Let's pretend that
+ it's always set. */
+ if (!interrupt_input && poll_suppress_count == 0)
{
SIGMASKTYPE mask;
mask = sigblock (sigmask (SIGALRM));
{
struct input_event buf[KBD_BUFFER_SIZE];
register int i;
- int nread;
-
+ int nread = 0;
+
for (i = 0; i < KBD_BUFFER_SIZE; i++)
EVENT_INIT (buf[i]);
- if (read_socket_hook)
- /* No need for FIONREAD or fcntl; just say don't wait. */
- nread = (*read_socket_hook) (input_fd, buf, KBD_BUFFER_SIZE, expected);
- else
+ {
+ struct display *d;
+
+ 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)
+ break;
+ }
+ }
+
+ if (nread <= 0 && tty_list)
{
/* 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;
-
- /* Determine how many characters we should *try* to read. */
+ struct tty_display_info *tty;
+ Lisp_Object frame;
+
#ifdef WINDOWSNT
return 0;
#else /* not WINDOWSNT */
n_to_read = dos_keysns ();
if (n_to_read == 0)
return 0;
+
+ cbuf[0] = dos_keyread ();
+ nread = 1;
+
#else /* not MSDOS */
+
+ nread = 0;
+
+ /* Try to read from each available tty, until one succeeds. */
+ for (tty = tty_list; tty; tty = tty->next) {
+
+ if (! tty->term_initted)
+ continue;
+
+ /* Determine how many characters we should *try* to read. */
#ifdef FIONREAD
- /* Find out how much input is available. */
- if (ioctl (input_fd, 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. */
- {
- if (! noninteractive)
- kill (getpid (), SIGHUP);
- else
- n_to_read = 0;
- }
- if (n_to_read == 0)
- return 0;
- 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)
+ {
+ /* 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;
#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 (input_fd, 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
-#endif /* not MSDOS */
-#endif /* not WINDOWSNT */
- /* Now read; for one reason or another, this will not block.
- NREAD is set to the number of chars read. */
- do
- {
-#ifdef MSDOS
- cbuf[0] = dos_keyread ();
- nread = 1;
-#else
- nread = emacs_read (input_fd, cbuf, n_to_read);
-#endif
- /* 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)
- kill (0, SIGHUP);
+ /* 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. */
+ }
#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)
- kill (0, SIGHUP);
-#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? */
+ /* 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. */
+ }
+#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? */
#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 (input_fd, 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;
+
+#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 (meta_key == 1 && (cbuf[i] & 0x80))
+ if (tty->meta_key == 1 && (cbuf[i] & 0x80))
buf[i].modifiers = meta_modifier;
- if (meta_key != 2)
+ if (tty->meta_key != 2)
cbuf[i] &= ~0x80;
- buf[i].code = cbuf[i];
- buf[i].frame_or_window = selected_frame;
+ buf[i].code = cbuf[i];
+ buf[i].frame_or_window = frame;
buf[i].arg = Qnil;
}
}
from an idle timer function. The symptom of the bug is that
the cursor sometimes doesn't become visible until the next X
event is processed. --gerd. */
- if (rif)
- rif->flush_display (NULL);
+ {
+ Lisp_Object tail, frame;
+ FOR_EACH_FRAME (tail, frame)
+ if (FRAME_RIF (XFRAME (frame)))
+ FRAME_RIF (XFRAME (frame))->flush_display (XFRAME (frame));
+ }
}
return input_pending;
int width, height;
struct gcpro gcpro1;
+ if (tty_list && tty_list->next)
+ error ("Suspend is not supported with multiple ttys");
+
if (!NILP (stuffstring))
CHECK_STRING (stuffstring);
call1 (Vrun_hooks, intern ("suspend-hook"));
GCPRO1 (stuffstring);
- get_frame_size (&old_width, &old_height);
- reset_sys_modes ();
+ get_tty_size (fileno (TTY_INPUT (CURTTY ())), &old_width, &old_height);
+ reset_all_sys_modes ();
/* sys_suspend can get an error if it tries to fork a subshell
and the system resources aren't available for that. */
record_unwind_protect ((Lisp_Object (*) P_ ((Lisp_Object))) init_sys_modes,
- Qnil);
+ (Lisp_Object)CURTTY()); /* XXX */
stuff_buffered_input (stuffstring);
if (cannot_suspend)
sys_subshell ();
/* Check if terminal/window size has changed.
Note that this is not useful when we are running directly
with a window system; but suspend should be disabled in that case. */
- get_frame_size (&width, &height);
+ get_tty_size (fileno (TTY_INPUT (CURTTY ())), &width, &height);
if (width != old_width || height != old_height)
change_frame_size (SELECTED_FRAME (), height, width, 0, 0, 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;
}
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. */
+ non-nil, it stops the job right away.
+
+ XXX This comment needs to be updated. */
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 ();
#if defined (USG) && !defined (POSIX_SIGNALS)
- if (!read_socket_hook && NILP (Vwindow_system))
+ /* USG systems forget handlers when they are used;
+ must reestablish each time */
+ signal (SIGINT, interrupt_signal);
+ signal (SIGQUIT, interrupt_signal);
+#endif /* USG */
+
+ if (! tty_list)
{
- /* USG systems forget handlers when they are used;
- must reestablish each time */
- signal (SIGINT, interrupt_signal);
- signal (SIGQUIT, interrupt_signal);
+ /* If there are no tty frames, exit Emacs.
+
+ Emacs should exit on SIGINT if and only if there are no
+ frames on its controlling tty and the signal came from there.
+ We can check for the first condition, but (alas) not for the
+ second. The best we can do is that we only exit if we are
+ sure that the SIGINT was from the controlling tty, i.e., if
+ there are no termcap frames.
+ */
+ Fkill_emacs (Qnil);
+
+ errno = old_errno;
+ return;
}
-#endif /* USG */
+
+ handle_interrupt ();
+
+ errno = old_errno;
+}
+
+/* C-g processing, signal independent code.
+
+ XXX Expand this comment. */
+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)))
{
sigblock (sigmask (SIGINT));
fflush (stdout);
- reset_sys_modes ();
+ reset_all_sys_modes ();
#ifdef SIGTSTP /* Support possible in later USG versions */
/*
printf ("Continuing...\n");
#endif /* not MSDOS */
fflush (stdout);
- init_sys_modes ();
+ init_all_sys_modes ();
sigfree ();
}
else
if (waiting_for_input && !echoing)
quit_throw_to_read_char ();
-
- errno = old_errno;
}
/* Handle a C-g by making read_char return C-g. */
(interrupt, flow, meta, quit)
Lisp_Object interrupt, flow, meta, quit;
{
+ /* XXX This function needs to be revised for multi-device support.
+ Currently it compiles fine, but its semantics are wrong. It sets
+ global parameters (e.g. interrupt_input) based on only the
+ current frame's device. */
+
if (!NILP (quit)
&& (!INTEGERP (quit) || XINT (quit) < 0 || XINT (quit) > 0400))
error ("set-input-mode: QUIT must be an ASCII character");
#ifndef DOS_NT
/* this causes startup screen to be restored and messes with the mouse */
- reset_sys_modes ();
+ if (FRAME_TERMCAP_P (SELECTED_FRAME ()))
+ reset_sys_modes (CURTTY ());
#endif
#ifdef SIGIO
/* Note SIGIO has been undef'd if FIONREAD is missing. */
- if (read_socket_hook)
+ if (FRAME_DISPLAY (SELECTED_FRAME ())->read_socket_hook)
{
/* When using X, don't give the user a real choice,
because we haven't implemented the mechanisms to support it. */
interrupt_input = 1;
#endif
- flow_control = !NILP (flow);
- if (NILP (meta))
- meta_key = 0;
- else if (EQ (meta, Qt))
- meta_key = 1;
- else
- meta_key = 2;
- if (!NILP (quit))
+ if (FRAME_TERMCAP_P (XFRAME (selected_frame)))
+ {
+ struct tty_display_info *tty = CURTTY ();
+ tty->flow_control = !NILP (flow);
+ if (NILP (meta))
+ tty->meta_key = 0;
+ else if (EQ (meta, Qt))
+ tty->meta_key = 1;
+ else
+ tty->meta_key = 2;
+ }
+
+ if (FRAME_TERMCAP_P (XFRAME (selected_frame)) && !NILP (quit))
/* Don't let this value be out of range. */
- quit_char = XINT (quit) & (meta_key ? 0377 : 0177);
+ quit_char = XINT (quit) & (CURTTY ()->meta_key ? 0377 : 0177);
#ifndef DOS_NT
- init_sys_modes ();
+ if (FRAME_TERMCAP_P (XFRAME (selected_frame)) && CURTTY ()->type)
+ init_sys_modes (CURTTY ());
#endif
#ifdef POLL_FOR_INPUT
()
{
Lisp_Object val[4];
-
+ struct frame *sf = XFRAME (selected_frame);
+
val[0] = interrupt_input ? Qt : Qnil;
- val[1] = flow_control ? Qt : Qnil;
- val[2] = meta_key == 2 ? make_number (0) : meta_key == 1 ? Qt : Qnil;
+ if (FRAME_TERMCAP_P (sf))
+ {
+ val[1] = FRAME_TTY (sf)->flow_control ? Qt : Qnil;
+ val[2] = FRAME_TTY (sf)->meta_key == 2
+ ? make_number (0)
+ : CURTTY ()->meta_key == 1 ? Qt : Qnil;
+ }
+ else
+ {
+ val[1] = Qnil;
+ val[2] = Qt;
+ }
XSETFASTINT (val[3], quit_char);
return Flist (sizeof (val) / sizeof (val[0]), val);
wipe_kboard (current_kboard);
init_kboard (current_kboard);
- if (!noninteractive && !read_socket_hook && NILP (Vwindow_system))
+ 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. */
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