Partially sync files.el from XEmacs 21.5 for wildcard support.
[sxemacs] / src / ui / TTY / cm.c
1 /* Cursor motion subroutines for SXEmacs.
2    Copyright (C) 1985, 1994, 1995 Free Software Foundation, Inc.
3     loosely based primarily on public domain code written by Chris Torek
4
5 This file is part of SXEmacs
6
7 SXEmacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 SXEmacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
19
20
21 /* Synched up with: FSF 19.30.  Substantially different from FSF. */
22
23 /* #### This file is extremely junky and needs major fixup. */
24
25 #include <config.h>
26 #include "lisp.h"
27
28 #include "console-tty.h"
29 #include "ui/frame.h"
30 #include "lstream.h"
31 #include "ui/redisplay.h"
32
33 #define EXPENSIVE 2000
34
35 EXTERN_C char *tgoto(const char *cm, int hpos, int vpos);
36 EXTERN_C int tputs(const char *, int, void (*)(int));
37
38 static void cmgoto_for_real(struct console *c, int row, int col);
39
40 static int cm_cost_counter;     /* sums up costs */
41
42 static void evalcost(int c)
43 {
44         cm_cost_counter++;
45 }
46
47 /* Ugh -- cmputc() can't take a console argument, so we pass it in a global */
48 struct console *cmputc_console;
49
50 void send_string_to_tty_console(struct console *c, unsigned char *str, int len)
51 {
52         /* #### Ben sez: don't some terminals need nulls outputted
53            for proper timing? */
54         Lstream *lstr = XLSTREAM(CONSOLE_TTY_DATA(c)->outstream);
55
56         if (CONSOLE_TTY_REAL_CURSOR_X(c) != CONSOLE_TTY_CURSOR_X(c)
57             || CONSOLE_TTY_REAL_CURSOR_Y(c) != CONSOLE_TTY_CURSOR_Y(c)) {
58                 int row = CONSOLE_TTY_CURSOR_Y(c);
59                 int col = CONSOLE_TTY_CURSOR_X(c);
60                 cmgoto_for_real(c, row, col);
61         }
62
63         if (len == 1)
64                 Lstream_putc(lstr, *str);
65         else if (len > 0)
66                 Lstream_write(lstr, str, len);
67 }
68
69 void cmputc(int c)
70 {
71         unsigned char ch = (unsigned char)c;
72
73         if (termscript)
74                 fputc(c, termscript);
75
76         send_string_to_tty_console(cmputc_console, &ch, 1);
77 }
78
79 #if 0
80
81 /*
82  * Terminals with magicwrap (xn) don't all behave identically.
83  * The VT100 leaves the cursor in the last column but will wrap before
84  * printing the next character.  I hear that the Concept terminal does
85  * the wrap immediately but ignores the next newline it sees.  And some
86  * terminals just have buggy firmware, and think that the cursor is still
87  * in limbo if we use direct cursor addressing from the phantom column.
88  * The only guaranteed safe thing to do is to emit a CRLF immediately
89  * after we reach the last column; this takes us to a known state.
90  */
91 void cmcheckmagic(void)
92 {
93         if (curX == FrameCols) {
94                 if (!MagicWrap || curY >= FrameRows - 1)
95                         abort();
96                 if (termscript)
97                         putc('\r', termscript);
98                 putchar('\r');
99                 if (termscript)
100                         putc('\n', termscript);
101                 putchar('\n');
102                 curX = 0;
103                 curY++;
104         }
105 }
106
107 #endif                          /* 0 */
108
109 /*
110  * (Re)Initialize the cost factors, given the output speed of the
111  * terminal in DEVICE_TTY_DATA (dev)->ospeed.  (Note: this holds B300,
112  * B9600, etc -- ie stuff out of <sgtty.h>.)
113  */
114 void cm_cost_init(struct console *c)
115 {
116         char *tmp;
117
118         cm_cost_counter = 0;
119 #define COST(x,e) (x \
120                    ? (cm_cost_counter = 0, tputs (x, 1, e), cm_cost_counter) \
121                    : EXPENSIVE)
122 #define MINCOST(x,e) ((x == 0) \
123                       ? EXPENSIVE \
124                       : (tmp = tgoto(x, 0, 0), COST(tmp,e)))
125
126         TTY_COST(c).cm_up = COST(TTY_CM(c).up, evalcost);
127         TTY_COST(c).cm_down = COST(TTY_CM(c).down, evalcost);
128         TTY_COST(c).cm_left = COST(TTY_CM(c).left, evalcost);
129         TTY_COST(c).cm_right = COST(TTY_CM(c).right, evalcost);
130         TTY_COST(c).cm_home = COST(TTY_CM(c).home, evalcost);
131         TTY_COST(c).cm_low_left = COST(TTY_CM(c).low_left, evalcost);
132         TTY_COST(c).cm_car_return = COST(TTY_CM(c).car_return, evalcost);
133
134         /*
135          * These last three are actually minimum costs.  When (if) they are
136          * candidates for the least-cost motion, the real cost is computed.
137          * (Note that "0" is the assumed to generate the minimum cost.
138          * While this is not necessarily true, I have yet to see a terminal
139          * for which is not; all the terminals that have variable-cost
140          * cursor motion seem to take straight numeric values.  --ACT)
141          */
142
143         TTY_COST(c).cm_abs = MINCOST(TTY_CM(c).abs, evalcost);
144         TTY_COST(c).cm_hor_abs = MINCOST(TTY_CM(c).hor_abs, evalcost);
145         TTY_COST(c).cm_ver_abs = MINCOST(TTY_CM(c).ver_abs, evalcost);
146
147 #undef MINCOST
148 #undef COST
149 }
150
151 /*
152  * Calculate the cost to move from (srcy, srcx) to (dsty, dstx) using
153  * up and down, and left and right, and motions.  If doit is set
154  * actually perform the motion.
155  */
156
157 #ifdef NOT_YET
158 static int
159 calccost(struct frame *f, int srcy, int srcx, int dsty, int dstx, int doit)
160 {
161         struct console *c = XCONSOLE(FRAME_CONSOLE(f));
162         int totalcost = 0;
163         int deltay, deltax;
164         char *motion;
165         int motion_cost;
166
167 #if 0
168         int ntabs, n2tabs, tabx, tab2x, tabcost;
169 #endif
170
171         cmputc_console = c;
172 #if 0
173         /* If have just wrapped on a terminal with xn,
174            don't believe the cursor position: give up here
175            and force use of absolute positioning.  */
176         if (curX == Wcm.cm_cols)
177                 goto fail;
178 #endif
179
180         deltay = dsty - srcy;
181         if (!deltay)
182                 goto calculate_x;
183
184         if (deltay < 0) {
185                 motion = TTY_CM(c).up;
186                 motion_cost = TTY_COST(c).cm_up;
187                 deltay = -deltay;
188         } else {
189                 motion = TTY_CM(c).down;
190                 motion_cost = TTY_COST(c).cm_down;
191         }
192
193         if (motion_cost == EXPENSIVE) {
194 /*      if (doit) */
195                 /* #### printing OOF is not acceptable */
196                 return motion_cost;
197         }
198
199         totalcost = motion_cost * deltay;
200
201         if (doit)
202                 while (--deltay >= 0)
203                         tputs(motion, 1, cmputc);
204
205       calculate_x:
206
207         deltax = dstx - srcx;
208         if (!deltax)
209                 goto done;
210
211         if (deltax < 0) {
212                 motion = TTY_CM(c).left;
213                 motion_cost = TTY_COST(c).cm_left;
214                 deltax = -deltax;
215         } else {
216                 motion = TTY_CM(c).right;
217                 motion_cost = TTY_COST(c).cm_right;
218         }
219
220         if (motion_cost == EXPENSIVE) {
221 /*      if (doit) */
222                 /* #### printing OOF is not acceptable */
223                 return motion_cost;
224         }
225
226         totalcost += motion_cost * deltax;
227
228         if (doit)
229                 while (--deltax >= 0)
230                         tputs(motion, 1, cmputc);
231
232       done:
233         return totalcost;
234 }
235 #endif                          /* NOT_YET */
236
237 #define USEREL  0
238 #define USEHOME 1
239 #define USELL   2
240 #define USECR   3
241
242 /*****************************************************************************
243  cmgoto
244
245  This function is responsible for getting the cursor from its current
246  location to the passed location in the most efficient manner
247  possible.
248  ****************************************************************************/
249 static void cmgoto_for_real(struct console *c, int row, int col)
250 {
251         char *motion;
252
253         cmputc_console = c;
254
255         /* First make sure that we actually have to do any work at all. */
256         if (CONSOLE_TTY_REAL_CURSOR_X(c) == col
257             && CONSOLE_TTY_REAL_CURSOR_Y(c) == row)
258                 return;
259
260         CONSOLE_TTY_REAL_CURSOR_X(c) = col;
261         CONSOLE_TTY_REAL_CURSOR_Y(c) = row;
262
263         /* #### Need to reimplement cost analysis and potential relative
264            movement. */
265
266         /* If all else fails, use absolute movement. */
267         motion = tgoto(TTY_CM(c).abs, col, row);
268         tputs(motion, 1, cmputc);
269         CONSOLE_TTY_CURSOR_X(c) = col;
270         CONSOLE_TTY_CURSOR_Y(c) = row;
271 }
272
273 void cmgoto(struct frame *f, int row, int col)
274 {
275         /* We delay cursor motion until we do something other than cursor motion,
276            to optimize the case where cmgoto() is called twice in a row. */
277         struct console *c = XCONSOLE(FRAME_CONSOLE(f));
278         CONSOLE_TTY_CURSOR_X(c) = col;
279         CONSOLE_TTY_CURSOR_Y(c) = row;
280 }
281
282 #if 0
283 /* Clear out all terminal info.
284    Used before copying into it the info on the actual terminal.
285  */
286
287 void Wcm_clear(void)
288 {
289         xzero(Wcm);
290         UP = 0;
291         BC = 0;
292 }
293 #endif
294
295 #if 0
296 /*
297  * Initialized stuff
298  * Return 0 if can do CM.
299  * Return -1 if cannot.
300  * Return -2 if size not specified.
301  */
302
303 int Wcm_init(void)
304 {
305 #if 0
306         if (Wcm.cm_abs && !Wcm.cm_ds)
307                 return 0;
308 #endif
309         if (Wcm.cm_abs)
310                 return 0;
311         /* Require up and left, and, if no absolute, down and right */
312         if (!Wcm.cm_up || !Wcm.cm_left)
313                 return -1;
314         if (!Wcm.cm_abs && (!Wcm.cm_down || !Wcm.cm_right))
315                 return -1;
316         /* Check that we know the size of the frame.... */
317         if (Wcm.cm_rows <= 0 || Wcm.cm_cols <= 0)
318                 return -2;
319         return 0;
320 }
321 #endif