chiark / gitweb /
Change James's email address
[sympathy.git] / src / terminal.c
1 /* 
2  * terminal.c:
3  *
4  * Copyright (c) 2008 James McKenzie <sympathy@madingley.org>,
5  * All rights reserved.
6  *
7  */
8
9 static char rcsid[] =
10   "$Id: terminal.c,v 1.24 2008/03/12 10:47:26 james Exp $";
11
12 /* 
13  * $Log: terminal.c,v $
14  * Revision 1.24  2008/03/12 10:47:26  james
15  * @@
16  *
17  * Revision 1.23  2008/03/12 01:30:23  james
18  * *** empty log message ***
19  *
20  * Revision 1.22  2008/03/11 17:56:50  james
21  * *** empty log message ***
22  *
23  * Revision 1.21  2008/03/11 17:56:04  james
24  * *** empty log message ***
25  *
26  * Revision 1.20  2008/03/10 11:49:33  james
27  * *** empty log message ***
28  *
29  * Revision 1.19  2008/03/07 14:16:44  james
30  * *** empty log message ***
31  *
32  * Revision 1.18  2008/03/07 14:13:40  james
33  * *** empty log message ***
34  *
35  * Revision 1.17  2008/03/07 13:16:02  james
36  * *** empty log message ***
37  *
38  * Revision 1.16  2008/03/07 12:42:08  james
39  * *** empty log message ***
40  *
41  * Revision 1.15  2008/03/07 12:37:04  james
42  * *** empty log message ***
43  *
44  * Revision 1.14  2008/03/03 06:04:42  james
45  * *** empty log message ***
46  *
47  * Revision 1.13  2008/03/02 10:37:56  james
48  * *** empty log message ***
49  *
50  * Revision 1.12  2008/02/28 16:57:52  james
51  * *** empty log message ***
52  *
53  * Revision 1.11  2008/02/26 23:56:12  james
54  * *** empty log message ***
55  *
56  * Revision 1.10  2008/02/26 23:23:17  james
57  * *** empty log message ***
58  *
59  * Revision 1.9  2008/02/15 03:32:07  james
60  * *** empty log message ***
61  *
62  * Revision 1.8  2008/02/14 10:39:14  james
63  * *** empty log message ***
64  *
65  * Revision 1.7  2008/02/14 01:55:57  james
66  * *** empty log message ***
67  *
68  * Revision 1.6  2008/02/14 00:57:58  james
69  * *** empty log message ***
70  *
71  * Revision 1.5  2008/02/13 18:05:06  james
72  * *** empty log message ***
73  *
74  * Revision 1.4  2008/02/13 16:57:29  james
75  * *** empty log message ***
76  *
77  * Revision 1.3  2008/02/13 09:12:21  james
78  * *** empty log message ***
79  *
80  * Revision 1.2  2008/02/13 01:08:18  james
81  * *** empty log message ***
82  *
83  * Revision 1.1  2008/02/12 22:36:46  james
84  * *** empty log message ***
85  *
86  * Revision 1.1  2008/02/09 15:47:28  james
87  * *** empty log message ***
88  *
89  * Revision 1.2  2008/02/07 11:11:14  staffcvs
90  * *** empty log message ***
91  *
92  * Revision 1.1  2008/02/07 01:02:52  james
93  * *** empty log message ***
94  *
95  * Revision 1.3  2008/02/06 17:53:28  james
96  * *** empty log message ***
97  *
98  * Revision 1.2  2008/02/04 02:05:06  james
99  * *** empty log message ***
100  *
101  * Revision 1.1  2008/02/04 01:32:39  james
102  * *** empty log message ***
103  *
104  */
105
106 #include "project.h"
107
108
109 typedef struct TERMINAL_struct {
110   TTY_SIGNATURE;
111   struct termios orig_termios;
112   struct TERMINAL_struct *next;
113 } TERMINAL;
114
115
116 static TERMINAL *terminal_list = NULL;
117 int terminal_winches;
118
119
120
121 static void
122 terminal_close (TTY * _t)
123 {
124   char buf[32];
125   int i;
126
127   TERMINAL *t = (TERMINAL *) _t;
128   TERMINAL **ptr = &terminal_list;
129
130   if (!t)
131     return;
132
133   /* Take out of cleanup list */
134   while (*ptr && (*ptr != t))
135     ptr = &((*ptr)->next);
136
137   if (*ptr)
138     *ptr = t->next;
139
140   tcsetattr (t->wfd, TCSANOW, &t->orig_termios);
141
142   set_nonblocking (t->wfd);
143
144
145   t->xmit (_t, "\033%@", 3);    // Leave UTF-8
146   t->xmit (_t, "\033(B", 3);    // US-ASCII in G0
147   t->xmit (_t, "\033)B", 3);    // US-ASCII in G1
148   t->xmit (_t, "\017", 1);      // Select G0
149   t->xmit (_t, "\033[?25h", 6); // Show cursor
150   t->xmit (_t, "\033[r", 3);    // No margins
151   t->xmit (_t, "\033[0m", 4);   // Default attributes
152   i = sprintf (buf, "\033[%d;%dH", t->displayed_length ? (t->displayed_length + 1) : (CRT_ROWS + 1), 1); 
153                 // Cursor to bottom
154   t->xmit (_t, buf, i);
155   t->xmit (_t, "\033[J", 3);    // erase rest of screen
156
157   set_blocking (t->rfd);
158   set_blocking (t->wfd);
159
160   free (t);
161 }
162
163
164 void
165 terminal_atexit (void)
166 {
167   while (terminal_list)
168     terminal_close ((TTY *) terminal_list);
169 }
170
171 static void
172 sigint (int dummy)
173 {
174   terminal_atexit ();
175   exit (-1);
176 }
177
178 static void
179 sigwinch (int not)
180 {
181   terminal_winches++;
182 }
183
184
185 void
186 terminal_getsize (TTY * _t)
187 {
188   TERMINAL *t = (TERMINAL *) _t;
189   struct winsize sz = { 0 };
190
191   if (!t)
192     return;
193
194   if (ioctl (t->wfd, TIOCGWINSZ, &sz)) {
195     t->size.x = CRT_COLS;
196     t->size.y = CRT_ROWS;
197   } else {
198     t->size.x = sz.ws_col;
199     t->size.y = sz.ws_row;
200   }
201 }
202
203
204 void
205 terminal_dispatch (void)
206 {
207   TERMINAL *t;
208
209
210   if (!terminal_winches)
211     return;
212
213   terminal_winches = 0;
214
215   for (t = terminal_list; t; t = t->next)
216     terminal_getsize ((TTY *) t);
217
218 }
219
220
221 static int
222 terminal_read (TTY * _t, void *buf, int len)
223 {
224   TERMINAL *t = (TERMINAL *) _t;
225   int red, done = 0;
226
227   terminal_dispatch ();
228   set_nonblocking (t->rfd);
229
230   do {
231
232     red = wrap_read (t->rfd, buf, len);
233     if (red < 0)
234       return -1;
235     if (!red)
236       return done;
237
238     buf += red;
239     len -= red;
240     done += red;
241   }
242   while (len);
243
244
245   return done;
246 }
247
248
249 static int
250 terminal_write (TTY * _t, void *buf, int len)
251 {
252   int writ, done = 0;
253   TERMINAL *t = (TERMINAL *) _t;
254
255   terminal_dispatch ();
256
257   set_blocking (t->wfd);
258
259   do {
260
261     writ = wrap_write (t->wfd, buf, len);
262     if (writ < 0)
263       return -1;
264
265     if (!writ)
266       usleep (1000);
267
268     buf += writ;
269     len -= writ;
270     done += writ;
271   }
272   while (len);
273
274
275   return done;
276 }
277
278
279 void
280 terminal_register_handlers (void)
281 {
282   struct sigaction sa = { 0 };
283
284   sa.sa_handler = sigwinch;
285   sa.sa_flags = SA_RESTART;
286   sigaction (SIGWINCH, &sa, NULL);
287
288   sa.sa_handler = sigint;
289   sa.sa_flags = SA_RESTART;
290   sigaction (SIGINT, &sa, NULL);
291 }
292
293
294 TTY *
295 terminal_open (int rfd, int wfd)
296 {
297   TERMINAL *t;
298   pid_t child;
299   struct termios termios;
300
301   t = (TERMINAL *) xmalloc (sizeof (TERMINAL));
302
303   strcpy (t->name, "terminal");
304   t->rfd = rfd;
305   t->wfd = wfd;
306
307   tcgetattr (wfd, &t->orig_termios);
308
309   t->next = terminal_list;
310   terminal_list = t;
311
312   tcgetattr (wfd, &termios);
313
314   set_nonblocking (rfd);
315   set_nonblocking (wfd);
316
317
318   cfmakeraw (&termios);
319   // raw_termios (&termios);
320
321   tcsetattr (wfd, TCSANOW, &termios);
322
323   t->recv = terminal_read;
324   t->xmit = terminal_write;
325   t->close = terminal_close;
326   t->blocked = 0;
327
328
329   terminal_getsize ((TTY *) t);
330
331   return (TTY *) t;
332 }