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