This is event-tty.c in view mode; [Download] [Up]
/* The event_stream interface for tty's.
Copyright (C) 1994, 1995 Board of Trustees, University of Illinois
This file is part of XEmacs.
XEmacs 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 2, or (at your option) any
later version.
XEmacs is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with XEmacs; see the file COPYING. If not, write to the Free
Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Synched up with: Not in FSF. */
#include <config.h>
#include "lisp.h"
#include "blocktype.h"
#include "device.h"
#include "device-tty.h"
#include "events.h"
#include "frame.h"
#include "process.h"
#include "sysproc.h"
#include "syswait.h"
#include "systime.h"
/* Mask of bits indicating the descriptors that we wait for input on */
extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
extern SELECT_TYPE process_only_mask, device_only_mask;
extern Lisp_Object Qdelete_device;
static struct event_stream *tty_event_stream;
/************************************************************************/
/* timeout events */
/************************************************************************/
/* The pending timers are stored in an ordered list, where the first timer
on the list is the first one to fire. Times recorded here are
absolute. */
static struct low_level_timeout *tty_timer_queue;
static int
emacs_tty_add_timeout (EMACS_TIME time)
{
return add_low_level_timeout (&tty_timer_queue, time);
}
static void
emacs_tty_remove_timeout (int id)
{
remove_low_level_timeout (&tty_timer_queue, id);
}
static void
tty_timeout_to_emacs_event (struct Lisp_Event *emacs_event)
{
emacs_event->event_type = timeout_event;
emacs_event->timestamp = 0; /* #### */
emacs_event->event.timeout.interval_id =
pop_low_level_timeout (&tty_timer_queue, 0);
}
static int
emacs_tty_event_pending_p (int user_p)
{
if (!user_p)
{
EMACS_TIME sometime;
/* see if there's a pending timeout. */
EMACS_GET_TIME (sometime);
if (tty_timer_queue &&
EMACS_TIME_EQUAL_OR_GREATER (sometime, tty_timer_queue->time))
return 1;
}
return poll_fds_for_input (user_p ? device_only_mask :
non_fake_input_wait_mask);
}
static struct device *
find_device_from_fd (int fd)
{
Lisp_Object rest;
DEVICE_LOOP (rest)
{
struct device *d;
assert (DEVICEP (XCAR (rest)));
d = XDEVICE (XCAR (rest));
if (DEVICE_IS_TTY (d) && fileno (DEVICE_TTY_DATA (d)->infd) == fd)
return d;
}
return 0;
}
int
read_event_from_tty_or_stream_desc (struct Lisp_Event *event,
struct device *d, int fd)
{
unsigned char ch;
int nread;
nread = read (fd, &ch, 1);
if (nread == 0)
{
Lisp_Object device;
XSETDEVICE (device, d);
/* deleting the device might not be safe right now ... */
Fenqueue_eval_event (Qdelete_device, device);
/* but we definitely need to unselect it to avoid infinite
loops reading EOF's */
Fdevice_disable_input (device);
}
else if (nread > 0)
{
character_to_event (ch, event, d);
event->channel = DEVICE_SELECTED_FRAME (d);
return 1;
}
else
{
/* #### What to do if there's an error? */
}
return 0;
}
int
maybe_read_quit_event (struct Lisp_Event *event)
{
/* A C-g that came from `sigint_happened' will always come from the
controlling terminal. If that doesn't exist, however, then the
user manually sent us a SIGINT, and we pretend the C-g came from
the selected-device. */
struct device *d;
if (DEVICEP (Vcontrolling_terminal) &&
DEVICE_LIVE_P (XDEVICE (Vcontrolling_terminal)))
d = XDEVICE (Vcontrolling_terminal);
else
d = XDEVICE (Fselected_device ());
if (sigint_happened)
{
int ch = DEVICE_QUIT_CHAR (d);
sigint_happened = 0;
Vquit_flag = Qnil;
character_to_event (ch, event, d);
event->channel = DEVICE_SELECTED_FRAME (d);
return 1;
}
return 0;
}
static void
emacs_tty_next_event (struct Lisp_Event *emacs_event)
{
while (1)
{
int ndesc;
int i;
SELECT_TYPE temp_mask = input_wait_mask;
EMACS_TIME time_to_block;
EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
if (!get_low_level_timeout_interval (tty_timer_queue, &time_to_block))
/* no timer events; block indefinitely */
pointer_to_this = 0;
else
{
EMACS_TIME_TO_SELECT_TIME (time_to_block, select_time_to_block);
pointer_to_this = &select_time_to_block;
}
ndesc = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
if (ndesc > 0)
{
/* Look for a TTY event */
for (i = 0; i < MAXDESC; i++)
{
/* To avoid race conditions (among other things, an infinite
loop when called from Fdiscard_input()), we must return
user events ahead of process events. */
if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &device_only_mask))
{
struct device *d = find_device_from_fd (i);
assert (d);
if (read_event_from_tty_or_stream_desc (emacs_event, d, i))
return;
}
}
/* Look for a process event */
for (i = 0; i < MAXDESC; i++)
{
if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &process_only_mask))
{
Lisp_Object process;
struct Lisp_Process *p =
get_process_from_input_descriptor (i);
assert (p);
XSETPROCESS (process, p);
emacs_event->event_type = process_event;
emacs_event->timestamp = 0; /* #### */
emacs_event->event.process.process = process;
return;
}
}
/* We might get here when a fake event came through a signal. */
/* Return a dummy event, so that a cycle of the command loop will
occur. */
drain_signal_event_pipe ();
emacs_event->event_type = eval_event;
emacs_event->event.eval.function = Qidentity;
emacs_event->event.eval.object = Qnil;
return;
}
else if (ndesc == 0) /* timeout fired */
{
tty_timeout_to_emacs_event (emacs_event);
return;
}
}
}
static void
emacs_tty_handle_magic_event (struct Lisp_Event *emacs_event)
{
/* Nothing to do currently */
}
static void
emacs_tty_select_process (struct Lisp_Process *process)
{
/* Nothing to do currently */
}
static void
emacs_tty_unselect_process (struct Lisp_Process *process)
{
/* Nothing to do currently */
}
static void
emacs_tty_select_device (struct device *d)
{
/* Nothing to do currently */
}
static void
emacs_tty_unselect_device (struct device *d)
{
/* Nothing to do currently */
}
static void
emacs_tty_quit_p (void)
{
/* Nothing to do currently because QUIT is handled through SIGINT.
This could change. */
}
/************************************************************************/
/* initialization */
/************************************************************************/
void
vars_of_event_tty (void)
{
tty_event_stream =
(struct event_stream *) xmalloc (sizeof (struct event_stream));
tty_event_stream->event_pending_p = emacs_tty_event_pending_p;
tty_event_stream->next_event_cb = emacs_tty_next_event;
tty_event_stream->handle_magic_event_cb = emacs_tty_handle_magic_event;
tty_event_stream->add_timeout_cb = emacs_tty_add_timeout;
tty_event_stream->remove_timeout_cb = emacs_tty_remove_timeout;
tty_event_stream->select_device_cb = emacs_tty_select_device;
tty_event_stream->unselect_device_cb = emacs_tty_unselect_device;
tty_event_stream->select_process_cb = emacs_tty_select_process;
tty_event_stream->unselect_process_cb = emacs_tty_unselect_process;
tty_event_stream->quit_p_cb = emacs_tty_quit_p;
}
void
init_event_tty_late (void)
{
event_stream = tty_event_stream;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.