/* 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.
#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;
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
Lisp_Object Qmenu_bar;
extern Lisp_Object Qleft_margin, Qright_margin;
extern Lisp_Object Qleft_fringe, Qright_fringe;
-extern Lisp_Object Qimage;
+extern Lisp_Object QCmap;
Lisp_Object recursive_edit_unwind (), command_loop ();
Lisp_Object Fthis_command_keys ();
/* 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
}
{
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;
}
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;
{
/* 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));
+ 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)));
- else if (CONSP (string) && EQ (XCAR (string), Qimage))
- object = string;
+ 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)
{
/* 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;
-
+ struct display *d;
+ 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
+ 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);
+
+ 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;
+ }
+
+ /* 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;
+ 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;
+ }
+
+ return nread;
+}
+
+/* This is the tty way of reading available input.
+
+ 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. */
- /* Determine how many characters we should *try* to read. */
+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;
+ return 0;
#else /* not WINDOWSNT */
#ifdef MSDOS
- n_to_read = dos_keysns ();
- if (n_to_read == 0)
- return 0;
+ 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)
+ return 0;
+
+ /* 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)
+ {
+ 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 (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)
+ {
+ 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)
- kill (0, SIGHUP);
+ /* 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 (input_fd, F_SETFL, 0);
+ fcntl (fileno (TTY_INPUT (tty)), F_SETFL, 0);
#endif /* USG or DGUX or CYGWIN */
#endif /* no FIONREAD */
- for (i = 0; i < nread; i++)
- {
- buf[i].kind = ASCII_KEYSTROKE_EVENT;
- buf[i].modifiers = 0;
- if (meta_key == 1 && (cbuf[i] & 0x80))
- buf[i].modifiers = meta_modifier;
- if (meta_key != 2)
- cbuf[i] &= ~0x80;
-
- buf[i].code = cbuf[i];
- buf[i].frame_or_window = selected_frame;
- buf[i].arg = Qnil;
- }
- }
-
- /* Scan the chars for C-g and store them in kbd_buffer. */
+
+ if (nread <= 0)
+ return nread;
+
+#endif /* not MSDOS */
+#endif /* not WINDOWSNT */
+
+ /* 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;
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;
discard_tty_input ();
kbd_fetch_ptr = kbd_store_ptr;
- Ffillarray (kbd_buffer_gcpro, Qnil);
input_pending = 0;
return Qnil;
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);
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.
+/* The SIGINT handler.
- 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.
-
- 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)
- 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 */
+
+ /* See if we have a display on our controlling terminal. */
+ display = get_named_tty_display (NULL);
+ if (!display)
{
- /* USG systems forget handlers when they are used;
- must reestablish each time */
- signal (SIGINT, interrupt_signal);
- signal (SIGQUIT, interrupt_signal);
+ /* If there are no frames there, let's pretend that we are a
+ well-behaving UN*X program and quit. */
+ Fkill_emacs (Qnil);
}
-#endif /* USG */
+ 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)))
{
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;
+ quit_throw_to_read_char ();
}
/* 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 ();
+ reset_all_sys_modes ();
#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 (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 (!NILP (quit))
/* Don't let this value be out of range. */
- quit_char = XINT (quit) & (meta_key ? 0377 : 0177);
+ quit_char = XINT (quit) & (NILP (meta) ? 0177 : 0377);
#ifndef DOS_NT
- init_sys_modes ();
+ init_all_sys_modes ();
#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);
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
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 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);