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