/* The event_stream interface for tty's. Copyright (C) 1994, 1995 Board of Trustees, University of Illinois. Copyright (C) 1995 Sun Microsystems, Inc. Copyright (C) 1995 Ben Wing.This file is part of XEmacs.XEmacs is free software; you can redistribute it and/or modify itunder the terms of the GNU General Public License as published by theFree Software Foundation; either version 2, or (at your option) anylater version.XEmacs is distributed in the hope that it will be useful, but WITHOUTANY WARRANTY; without even the implied warranty of MERCHANTABILITY orFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licensefor more details.You should have received a copy of the GNU General Public Licensealong with XEmacs; see the file COPYING. If not, write tothe Free Software Foundation, Inc., 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. *//* Synched up with: Not in FSF. */#include <config.h>#include "lisp.h"#include "blocktype.h"#include "device.h"#include "console-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 */externSELECT_TYPEinput_wait_mask,non_fake_input_wait_mask;externSELECT_TYPEprocess_only_mask,tty_only_mask;externLisp_ObjectQdelete_device;staticstructevent_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. */staticstructlow_level_timeout*tty_timer_queue;staticintemacs_tty_add_timeout(EMACS_TIMEthyme){returnadd_low_level_timeout(&tty_timer_queue,thyme);}staticvoidemacs_tty_remove_timeout(intid){remove_low_level_timeout(&tty_timer_queue,id);}staticvoidtty_timeout_to_emacs_event(structLisp_Event*emacs_event){emacs_event->event_type=timeout_event;/* timeout events have nil as channel */emacs_event->timestamp=0;/* #### */emacs_event->event.timeout.interval_id=pop_low_level_timeout(&tty_timer_queue,0);}staticintemacs_tty_event_pending_p(intuser_p){if(!user_p){EMACS_TIMEsometime;/* 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))return1;}returnpoll_fds_for_input(user_p?tty_only_mask:non_fake_input_wait_mask);}staticstructconsole*find_console_from_fd(intfd){Lisp_Objectconcons;CONSOLE_LOOP(concons){structconsole*c;c=XCONSOLE(XCAR(concons));if(CONSOLE_TTY_P(c)&&CONSOLE_TTY_DATA(c)->infd==fd)returnc;}return0;}staticvoidemacs_tty_next_event(structLisp_Event*emacs_event){while(1){intndesc;inti;SELECT_TYPEtemp_mask=input_wait_mask;EMACS_TIMEtime_to_block;EMACS_SELECT_TIMEselect_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,&tty_only_mask)){structconsole*c=find_console_from_fd(i);assert(c);if(read_event_from_tty_or_stream_desc(emacs_event,c,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_Objectprocess;structLisp_Process*p=get_process_from_input_descriptor(i);assert(p);XSETPROCESS(process,p);emacs_event->event_type=process_event;/* process events have nil as channel */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;/* eval events have nil as channel */emacs_event->event.eval.function=Qidentity;emacs_event->event.eval.object=Qnil;return;}elseif(ndesc==0)/* timeout fired */{tty_timeout_to_emacs_event(emacs_event);return;}}}staticvoidemacs_tty_handle_magic_event(structLisp_Event*emacs_event){/* Nothing to do currently */}staticvoidemacs_tty_select_process(structLisp_Process*process){event_stream_unixoid_select_process(process);}staticvoidemacs_tty_unselect_process(structLisp_Process*process){event_stream_unixoid_unselect_process(process);}staticvoidemacs_tty_select_console(structconsole*con){event_stream_unixoid_select_console(con);}staticvoidemacs_tty_unselect_console(structconsole*con){event_stream_unixoid_unselect_console(con);}staticvoidemacs_tty_quit_p(void){/* Nothing to do currently because QUIT is handled through SIGINT. This could change. */}/************************************************************************//* initialization *//************************************************************************/voidvars_of_event_tty(void){tty_event_stream=(structevent_stream*)xmalloc(sizeof(structevent_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_console_cb=emacs_tty_select_console;tty_event_stream->unselect_console_cb=emacs_tty_unselect_console;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;}voidinit_event_tty_late(void){event_stream=tty_event_stream;}