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.