XEmacs 21.2-b1
[chise/xemacs-chise.git.1] / src / event-tty.c
1 /* The event_stream interface for tty's.
2    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3    Copyright (C) 1995 Sun Microsystems, Inc.
4    Copyright (C) 1995 Ben Wing.
5
6 This file is part of XEmacs.
7
8 XEmacs is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
11 later version.
12
13 XEmacs is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with XEmacs; see the file COPYING.  If not, write to
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.  */
22
23 /* Synched up with: Not in FSF. */
24
25 #include <config.h>
26 #include "lisp.h"
27
28 #include "device.h"
29 #include "console-tty.h"
30 #include "events.h"
31 #include "frame.h"
32 #include "process.h"
33
34 #include "sysproc.h"
35 #include "syswait.h"
36 #include "systime.h"
37
38 /* Mask of bits indicating the descriptors that we wait for input on */
39 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
40 extern SELECT_TYPE process_only_mask, tty_only_mask;
41
42 static struct event_stream *tty_event_stream;
43
44 \f
45 /************************************************************************/
46 /*                              timeout events                          */
47 /************************************************************************/
48
49 /* The pending timers are stored in an ordered list, where the first timer
50    on the list is the first one to fire.  Times recorded here are
51    absolute. */
52 static struct low_level_timeout *tty_timer_queue;
53
54 static int
55 emacs_tty_add_timeout (EMACS_TIME thyme)
56 {
57   return add_low_level_timeout (&tty_timer_queue, thyme);
58 }
59
60 static void
61 emacs_tty_remove_timeout (int id)
62 {
63   remove_low_level_timeout (&tty_timer_queue, id);
64 }
65
66 static void
67 tty_timeout_to_emacs_event (struct Lisp_Event *emacs_event)
68 {
69   emacs_event->event_type = timeout_event;
70   /* timeout events have nil as channel */
71   emacs_event->timestamp  = 0; /* #### */
72   emacs_event->event.timeout.interval_id =
73     pop_low_level_timeout (&tty_timer_queue, 0);
74 }
75
76 \f
77
78 static int
79 emacs_tty_event_pending_p (int user_p)
80 {
81   if (!user_p)
82     {
83       EMACS_TIME sometime;
84       /* see if there's a pending timeout. */
85       EMACS_GET_TIME (sometime);
86       if (tty_timer_queue &&
87           EMACS_TIME_EQUAL_OR_GREATER (sometime, tty_timer_queue->time))
88         return 1;
89     }
90
91   return poll_fds_for_input (user_p ? tty_only_mask :
92                              non_fake_input_wait_mask);
93 }
94
95 static struct console *
96 find_console_from_fd (int fd)
97 {
98   Lisp_Object concons;
99
100   CONSOLE_LOOP (concons)
101     {
102       struct console *c;
103
104       c = XCONSOLE (XCAR (concons));
105       if (CONSOLE_TTY_P (c) && CONSOLE_TTY_DATA (c)->infd == fd)
106         return c;
107     }
108
109   return 0;
110 }
111
112 static void
113 emacs_tty_next_event (struct Lisp_Event *emacs_event)
114 {
115   while (1)
116     {
117       int ndesc;
118       int i;
119       SELECT_TYPE temp_mask = input_wait_mask;
120       EMACS_TIME time_to_block;
121       EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
122
123       if (!get_low_level_timeout_interval (tty_timer_queue, &time_to_block))
124         /* no timer events; block indefinitely */
125         pointer_to_this = 0;
126       else
127         {
128           EMACS_TIME_TO_SELECT_TIME (time_to_block, select_time_to_block);
129           pointer_to_this = &select_time_to_block;
130         }
131
132       ndesc = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
133       if (ndesc > 0)
134         {
135           /* Look for a TTY event */
136           for (i = 0; i < MAXDESC; i++)
137             {
138               /* To avoid race conditions (among other things, an infinite
139                  loop when called from Fdiscard_input()), we must return
140                  user events ahead of process events. */
141               if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
142                 {
143                   struct console *c = find_console_from_fd (i);
144
145                   assert (c);
146                   if (read_event_from_tty_or_stream_desc (emacs_event, c, i))
147                     return;
148                 }
149             }
150
151           /* Look for a process event */
152           for (i = 0; i < MAXDESC; i++)
153             {
154               if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &process_only_mask))
155                 {
156                   Lisp_Object process;
157                   struct Lisp_Process *p =
158                     get_process_from_usid (FD_TO_USID(i));
159
160                   assert (p);
161                   XSETPROCESS (process, p);
162                   emacs_event->event_type = process_event;
163                   /* process events have nil as channel */
164                   emacs_event->timestamp  = 0; /* #### */
165                   emacs_event->event.process.process = process;
166                   return;
167                 }
168             }
169
170           /* We might get here when a fake event came through a signal. */
171           /* Return a dummy event, so that a cycle of the command loop will
172              occur. */
173           drain_signal_event_pipe ();
174           emacs_event->event_type = eval_event;
175           /* eval events have nil as channel */
176           emacs_event->event.eval.function = Qidentity;
177           emacs_event->event.eval.object = Qnil;
178           return;
179         }
180       else if (ndesc == 0) /* timeout fired */
181         {
182           tty_timeout_to_emacs_event (emacs_event);
183           return;
184         }
185     }
186 }
187
188 static void
189 emacs_tty_handle_magic_event (struct Lisp_Event *emacs_event)
190 {
191   /* Nothing to do currently */
192 }
193
194 \f
195 static void
196 emacs_tty_select_process (struct Lisp_Process *process)
197 {
198   event_stream_unixoid_select_process (process);
199 }
200
201 static void
202 emacs_tty_unselect_process (struct Lisp_Process *process)
203 {
204   event_stream_unixoid_unselect_process (process);
205 }
206
207 static void
208 emacs_tty_select_console (struct console *con)
209 {
210   event_stream_unixoid_select_console (con);
211 }
212
213 static void
214 emacs_tty_unselect_console (struct console *con)
215 {
216   event_stream_unixoid_unselect_console (con);
217 }
218
219 static void
220 emacs_tty_quit_p (void)
221 {
222   /* Nothing to do currently because QUIT is handled through SIGINT.
223      This could change. */
224 }
225
226 static USID
227 emacs_tty_create_stream_pair (void* inhandle, void* outhandle,
228                 Lisp_Object* instream, Lisp_Object* outstream, int flags)
229 {
230   return event_stream_unixoid_create_stream_pair
231                 (inhandle, outhandle, instream, outstream, flags);
232 }
233
234 static USID
235 emacs_tty_delete_stream_pair (Lisp_Object instream, Lisp_Object outstream)
236 {
237   return event_stream_unixoid_delete_stream_pair (instream, outstream);
238 }
239
240 \f
241 /************************************************************************/
242 /*                            initialization                            */
243 /************************************************************************/
244
245 void
246 vars_of_event_tty (void)
247 {
248   tty_event_stream = xnew (struct event_stream);
249
250   tty_event_stream->event_pending_p     = emacs_tty_event_pending_p;
251   tty_event_stream->next_event_cb       = emacs_tty_next_event;
252   tty_event_stream->handle_magic_event_cb = emacs_tty_handle_magic_event;
253   tty_event_stream->add_timeout_cb      = emacs_tty_add_timeout;
254   tty_event_stream->remove_timeout_cb   = emacs_tty_remove_timeout;
255   tty_event_stream->select_console_cb   = emacs_tty_select_console;
256   tty_event_stream->unselect_console_cb = emacs_tty_unselect_console;
257   tty_event_stream->select_process_cb   = emacs_tty_select_process;
258   tty_event_stream->unselect_process_cb = emacs_tty_unselect_process;
259   tty_event_stream->quit_p_cb           = emacs_tty_quit_p;
260   tty_event_stream->create_stream_pair_cb = emacs_tty_create_stream_pair;
261   tty_event_stream->delete_stream_pair_cb = emacs_tty_delete_stream_pair;
262 }
263
264 void
265 init_event_tty_late (void)
266 {
267   event_stream = tty_event_stream;
268 }