Initial git import
[sxemacs] / src / ui / TTY / 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 SXEmacs
7
8 SXEmacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 SXEmacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
20
21
22 /* Synched up with: Not in FSF. */
23
24 #include <config.h>
25 #include "lisp.h"
26
27 #include "ui/device.h"
28 #include "console-tty.h"
29 #define INCLUDE_EVENTS_H_PRIVATE_SPHERE
30 #include "events/events.h"
31 #include "ui/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 \f
44 /************************************************************************/
45 /*                              timeout events                          */
46 /************************************************************************/
47
48 /* The pending timers are stored in an ordered list, where the first timer
49    on the list is the first one to fire.  Times recorded here are
50    absolute. */
51 static struct low_level_timeout *tty_timer_queue;
52 static Lisp_Object dispatch_event_queue;
53 static Lisp_Object UNUSED(dispatch_event_queue_tail);
54 static int last_quit_check_signal_tick_count;
55
56 static int
57 emacs_tty_add_timeout(EMACS_TIME thyme)
58 {
59         return add_low_level_timeout(&tty_timer_queue, thyme);
60 }
61
62 static void
63 emacs_tty_remove_timeout(int id)
64 {
65         remove_low_level_timeout(&tty_timer_queue, id);
66 }
67
68 static void
69 tty_timeout_to_emacs_event(Lisp_Event * emacs_event)
70 {
71         emacs_event->event_type = timeout_event;
72         /* timeout events have nil as channel */
73         emacs_event->timestamp = 0;     /* #### */
74         emacs_event->event.timeout.interval_id =
75             pop_low_level_timeout(&tty_timer_queue, 0);
76         emacs_event->event.timeout.function = Qnil;
77         emacs_event->event.timeout.object = Qnil;
78 }
79 \f
80 static int
81 emacs_tty_event_pending_p(int user_p)
82 {
83         Lisp_Object event;
84         int         tick_val;
85
86         if (!user_p) {
87                 EMACS_TIME sometime;
88
89                 /* (1) Any pending events in the dispatch queue? */
90                 if (!NILP(dispatch_event_queue))
91                         return 1;
92                 
93                 /* (2) Any TTY or process input available? */
94                 if (poll_fds_for_input (non_fake_input_wait_mask))
95                         return 1;
96
97                 /* (3) Any timeout input available? */
98                 EMACS_GET_TIME(sometime);
99                 if (tty_timer_queue &&
100                     EMACS_TIME_EQUAL_OR_GREATER(sometime,
101                                                 tty_timer_queue->time))
102                         return 1;
103         } else {
104                 /* HOW_MANY > 0 */
105                 EVENT_CHAIN_LOOP (event, dispatch_event_queue)
106                 {
107                         if (command_event_p (event))
108                         {
109                                 return 1;
110                         }
111                 }
112         }
113         tick_val = quit_check_signal_tick_count;
114
115         if (last_quit_check_signal_tick_count != tick_val)
116         {
117                 last_quit_check_signal_tick_count = tick_val;
118                 /* We need to drain the entire queue now -- if we only drain part of
119                    it, we may later on end up with events actually pending but
120                    detect_input_pending() returning false because there wasn't
121                    another SIGIO. */
122 #if 0
123                 event_stream_drain_queue ();
124 #endif
125                 
126                 if (!user_p)
127                         return !NILP (dispatch_event_queue);
128                 
129                 EVENT_CHAIN_LOOP (event, dispatch_event_queue)
130                 {
131                         if (command_event_p (event))
132                                 return 1;
133                 }
134         }
135         return poll_fds_for_input(user_p ? tty_only_mask :
136                                   non_fake_input_wait_mask);
137 }
138
139 struct console*
140 tty_find_console_from_fd(int fd)
141 {
142         Lisp_Object concons;
143
144         CONSOLE_LOOP(concons) {
145                 struct console *c;
146
147                 c = XCONSOLE(XCAR(concons));
148                 if (CONSOLE_TTY_P(c) && CONSOLE_TTY_DATA(c)->infd == fd)
149                         return c;
150         }
151
152         return 0;
153 }
154
155 static void
156 emacs_tty_next_event(Lisp_Event * emacs_event)
157 {
158         int ndesc;
159         unsigned i;
160         SELECT_TYPE temp_mask;
161         EMACS_TIME time_to_block;
162         EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
163
164         struct console *c;
165         Lisp_Process *p;
166
167         /* Wait for some event */
168         while (1) {
169                 temp_mask = input_wait_mask;
170
171                 if (!get_low_level_timeout_interval(tty_timer_queue, &time_to_block))
172                         /* no timer events; block indefinitely */
173                         pointer_to_this = 0;
174                 else {
175                         EMACS_TIME_TO_SELECT_TIME(time_to_block, select_time_to_block);
176                         pointer_to_this = &select_time_to_block;
177                 }
178
179                 ndesc = select(MAXDESC, &temp_mask, 0, 0, pointer_to_this);
180                 if (ndesc == 0) {
181                         tty_timeout_to_emacs_event(emacs_event);
182                         return;
183                 } else if (ndesc > 0)
184                         break;
185         }
186
187         /* Look for a TTY event */
188         for (i = 0; i < MAXDESC; i++) {
189                 /* To avoid race conditions (among other things, an infinite
190                    loop when called from Fdiscard_input()), we must return
191                    user events ahead of process events. */
192                 if (!FD_ISSET(i, &temp_mask) || !FD_ISSET(i, &tty_only_mask))
193                         continue;
194
195                 c = tty_find_console_from_fd(i);
196                 assert(c);
197                 if (read_event_from_tty_or_stream_desc(emacs_event, c, i))
198                         return;
199         }
200
201         /* Look for a process event */
202         for (i = 0; i < MAXDESC; i++) {
203                 if (!FD_ISSET(i, &temp_mask) || !FD_ISSET(i, &process_only_mask))
204                         continue;
205
206                 p = get_process_from_usid(FD_TO_USID(i));
207                 assert(p);
208
209                 XSETPROCESS(emacs_event->event.process.process, p);
210                 emacs_event->event_type = process_event;
211                 /* process events have nil as channel */
212                 emacs_event->timestamp = 0;     /* #### */
213                 return;
214         }
215
216         /* We might get here when a fake event came through a signal. */
217         /* Return a dummy event, so that a cycle of the command loop will
218            occur. */
219         drain_signal_event_pipe();
220         emacs_event->event_type = eval_event;
221         /* eval events have nil as channel */
222         emacs_event->event.eval.function = Qidentity;
223         emacs_event->event.eval.object = Qnil;
224 }
225
226 static void
227 emacs_tty_handle_magic_event(Lisp_Event * emacs_event)
228 {
229         /* Nothing to do currently */
230 }
231 \f
232 static void
233 emacs_tty_select_process(Lisp_Process * process)
234 {
235         event_stream_unixoid_select_process(process);
236 }
237
238 static void
239 emacs_tty_unselect_process(Lisp_Process * process)
240 {
241         event_stream_unixoid_unselect_process(process);
242 }
243
244 static void
245 emacs_tty_select_console(struct console *con)
246 {
247         event_stream_unixoid_select_console(con);
248 }
249
250 static void
251 emacs_tty_unselect_console(struct console *con)
252 {
253         event_stream_unixoid_unselect_console(con);
254 }
255
256 static void
257 emacs_tty_quit_p(void)
258 {
259         /* Nothing to do currently because QUIT is handled through SIGINT.
260            This could change. */
261 }
262
263 static USID
264 emacs_tty_create_stream_pair(void *inhandle, void *outhandle,
265                              Lisp_Object * instream, Lisp_Object * outstream,
266                              int flags)
267 {
268         return event_stream_unixoid_create_stream_pair
269             (inhandle, outhandle, instream, outstream, flags);
270 }
271
272 static USID
273 emacs_tty_delete_stream_pair(Lisp_Object instream, Lisp_Object outstream)
274 {
275         return event_stream_unixoid_delete_stream_pair(instream, outstream);
276 }
277 \f
278 /************************************************************************/
279 /*                            initialization                            */
280 /************************************************************************/
281
282 void
283 reinit_vars_of_event_tty(void)
284 {
285         tty_event_stream = xnew(struct event_stream);
286
287         tty_event_stream->event_pending_p = emacs_tty_event_pending_p;
288         tty_event_stream->force_event_pending = 0;
289         tty_event_stream->next_event_cb = emacs_tty_next_event;
290         tty_event_stream->handle_magic_event_cb = emacs_tty_handle_magic_event;
291         tty_event_stream->add_timeout_cb = emacs_tty_add_timeout;
292         tty_event_stream->remove_timeout_cb = emacs_tty_remove_timeout;
293         tty_event_stream->select_console_cb = emacs_tty_select_console;
294         tty_event_stream->unselect_console_cb = emacs_tty_unselect_console;
295         tty_event_stream->select_process_cb = emacs_tty_select_process;
296         tty_event_stream->unselect_process_cb = emacs_tty_unselect_process;
297         tty_event_stream->quit_p_cb = emacs_tty_quit_p;
298         tty_event_stream->create_stream_pair_cb = emacs_tty_create_stream_pair;
299         tty_event_stream->delete_stream_pair_cb = emacs_tty_delete_stream_pair;
300
301         last_quit_check_signal_tick_count = 0;
302 }
303
304 void
305 vars_of_event_tty(void)
306 {
307         reinit_vars_of_event_tty();
308
309         dispatch_event_queue = Qnil;
310         staticpro(&dispatch_event_queue);
311 }
312
313 void
314 init_event_tty_late(void)
315 {
316         event_stream = tty_event_stream;
317 }