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