chiark / gitweb /
bdc3a56ce899911288267b2352c042f39e75b9d2
[sympathy.git] / src / ansi.c
1 /*
2  * ansi.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.5  2008/02/06 15:53:22  james
14  * *** empty log message ***
15  *
16  * Revision 1.4  2008/02/04 20:23:55  james
17  * *** empty log message ***
18  *
19  * Revision 1.3  2008/02/04 05:45:55  james
20  * ::
21  *
22  * Revision 1.2  2008/02/04 02:05:06  james
23  * *** empty log message ***
24  *
25  * Revision 1.1  2008/02/03 23:31:25  james
26  * *** empty log message ***
27  *
28  */
29 #include "project.h"
30
31 void
32 ansi_write (ANSI * a, char *buf, int n)
33 {
34   write (a->fd, buf, n);
35 }
36
37 void
38 ansi_getsize (ANSI * a)
39 {
40   struct winsize sz = { 0 };
41   if (ioctl (a->fd, TIOCGWINSZ, &sz))
42     {
43       a->size.x = CRT_COLS;
44       a->size.y = CRT_ROWS;
45     }
46   else
47     {
48       a->size.x = sz.ws_col;
49       a->size.y = sz.ws_row;
50     }
51
52 }
53
54
55 void
56 ansi_move (ANSI * a, CRT_Pos p)
57 {
58   char buf[16];
59   int n;
60   int dx = p.x - a->pos.x;
61   int dy = p.y - a->pos.y;
62
63 //  a->pos.x = ANSI_INVAL;
64
65   if (a->pos.x != ANSI_INVAL)
66     {
67
68       if ((!dx) && (!dy))
69         return;
70
71       if (!dy)
72         {
73           if (dx == 1)
74             {
75               ansi_write (a, "\033[C", 3);
76             }
77           else if (dx == -1)
78             {
79               ansi_write (a, "\033[D", 3);
80             }
81           else
82             {
83               n = snprintf (buf, sizeof (buf), "\033[%dG", p.x + 1);
84               ansi_write (a, buf, n);
85             }
86         }
87       else if (!dx)
88         {
89           if (dy == -1)
90             {
91               ansi_write (a, "\033[A", 3);
92             }
93           else if (dy == 1)
94             {
95               ansi_write (a, "\033[B", 3);
96             }
97           else if (dy < 0)
98             {
99               n = snprintf (buf, sizeof (buf), "\033[%dA", -dy);
100               ansi_write (a, buf, n);
101             }
102           else
103             {
104               n = snprintf (buf, sizeof (buf), "\033[%dB", dy);
105               ansi_write (a, buf, n);
106             }
107         }
108       else if (!p.x)
109         {
110           if (dy == 1)
111             {
112               ansi_write (a, "\033[E", 3);
113             }
114           else if (dy == -1)
115             {
116               ansi_write (a, "\033[F", 3);
117             }
118           else if (dy > 0)
119             {
120               n = snprintf (buf, sizeof (buf), "\033[%dE", dy);
121               ansi_write (a, buf, n);
122             }
123           else
124             {
125               n = snprintf (buf, sizeof (buf), "\033[%dF", -dy);
126               ansi_write (a, buf, n);
127             }
128         }
129       else
130         {
131           n = snprintf (buf, sizeof (buf), "\033[%d;%dH", p.y + 1, p.x + 1);
132           ansi_write (a, buf, n);
133         }
134     }
135   else
136     {
137       n = snprintf (buf, sizeof (buf), "\033[%d;%dH", p.y + 1, p.x + 1);
138       ansi_write (a, buf, n);
139     }
140
141   a->pos = p;
142 }
143
144
145 void
146 ansi_showhide_cursor (ANSI * a, int hide)
147 {
148   if (a->hide_cursor == hide)
149     return;
150
151   if (hide)
152     {
153       ansi_write (a, "\033[?25l", 6);
154     }
155   else
156     {
157       ansi_write (a, "\033[?25h", 6);
158     }
159
160   a->hide_cursor = hide;
161 }
162
163
164 void
165 ansi_force_attr_normal (ANSI * a)
166 {
167   ansi_write (a, "\033[0m", 4);
168   a->attr = CRT_ATTR_NORMAL;
169 }
170
171 void
172 ansi_set_attr (ANSI * a, int attr)
173 {
174   int dif;
175
176   dif = attr ^ a->attr;
177
178   if (!dif)
179     return;
180
181   a->attr = attr;
182
183   if (attr == CRT_ATTR_NORMAL)
184     {
185       ansi_force_attr_normal (a);
186       return;
187     }
188
189   if (dif & CRT_ATTR_UNDERLINE)
190     {
191       if (attr & CRT_ATTR_UNDERLINE)
192         {
193           ansi_write (a, "\033[4m", 4);
194         }
195       else
196         {
197           ansi_write (a, "\033[24m", 5);
198         }
199     }
200   if (dif & CRT_ATTR_REVERSE)
201     {
202       if (attr & CRT_ATTR_REVERSE)
203         {
204           ansi_write (a, "\033[7m", 4);
205         }
206       else
207         {
208           ansi_write (a, "\033[27m", 5);
209         }
210     }
211   if (dif & CRT_ATTR_BOLD)
212     {
213       if (attr & CRT_ATTR_BOLD)
214         {
215           ansi_write (a, "\033[1m", 4);
216         }
217       else
218         {
219           ansi_write (a, "\033[22m", 5);
220         }
221     }
222
223 }
224
225
226 void
227 ansi_render (ANSI * a, CRT_CA ca)
228 {
229   int dif;
230
231   if (ca.chr < 32)
232     ca.chr = ' ';
233   if (ca.chr > 126)
234     ca.chr = ' ';
235
236   ansi_set_attr (a, ca.attr);
237
238   ansi_write (a, &ca.chr, 1);
239
240   a->pos.x++;
241
242 /*Can't easily wrap round here as don't know size of destination screen*/
243 /*so invalidate the cached cursor position*/
244
245   if (a->pos.x >= CRT_COLS)
246     a->pos.x = ANSI_INVAL;
247
248 }
249
250 void
251 ansi_cls (ANSI * a)
252 {
253   CRT_Pos p = { 0 };
254
255   crt_cls (&a->crt);
256
257   ansi_force_attr_normal (a);
258   ansi_move (a, p);
259   ansi_write (a, "\033[2J", 4);
260 /*different emulators leave cursor in different places after cls differently*/
261   a->pos.x = ANSI_INVAL;
262 }
263
264
265 void
266 ansi_draw (ANSI * a, CRT * c)
267 {
268   CRT_Pos p;
269   int o;
270
271   ansi_showhide_cursor (a, 1);
272
273   for (p.y = 0; p.y < CRT_ROWS; ++p.y)
274     {
275       if (p.y >= a->size.y)
276         continue;
277       o = CRT_ADDR (p.y, 0);
278       for (p.x = 0; p.x < CRT_COLS; ++p.x, ++o)
279         {
280           if (p.x >= a->size.x)
281             continue;
282           if (crt_ca_cmp (a->crt.screen[o], c->screen[o]))
283             {
284               a->crt.screen[o] = c->screen[o];
285
286               ansi_move (a, p);
287               ansi_render (a, a->crt.screen[o]);
288             }
289         }
290     }
291
292   a->crt.pos = c->pos;
293   ansi_move (a, a->crt.pos);
294
295   a->crt.hide_cursor = c->hide_cursor;
296   ansi_showhide_cursor (a, a->crt.hide_cursor);
297 }
298
299 void
300 ansi_reset (ANSI * a)
301 {
302 // FIXME: -- echos back crap?
303 //  ansi_write (a, "\033[c", 3);
304   ansi_getsize (a);
305
306   a->pos.x = ANSI_INVAL;
307   a->hide_cursor = ANSI_INVAL;
308
309   crt_reset (&a->crt);
310
311   ansi_cls (a);
312   ansi_draw (a, &a->crt);
313 }