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