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