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