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