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