1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1997 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 /*LINTLIBRARY*/ 43 44 #include <sys/types.h> 45 #include "curses_inc.h" 46 47 /* 48 * Cursor motion optimization routine. This routine takes as parameters 49 * the screen positions that the cursor is currently at, and the position 50 * you want it to be at, and it will move the cursor there very 51 * efficiently. It isn't really optimal, since several approximations 52 * are taken in the interests of efficiency and simplicity. The code 53 * here considers directly addressing the cursor, and also considers 54 * local motions using left, right, up, down, tabs, backtabs, vertical 55 * and horizontal addressing, and parameterized motions. It does not 56 * consider using home down, or taking advantage of automatic margins on 57 * any of the four directions. (Two of these directions, left and right, 58 * are well defined by the am and bw capabilities, but up and down are 59 * not defined, nor are tab or backtab off the ends.) 60 * 61 * General strategies considered: 62 * CA Direct Cursor Addressing 63 * LM Local Motions from the old position 64 * HR Home + Local Motions from upper left corner 65 * HDR Home Down + Local Motions from lower left corner 66 * CR CR + Local Motions from left margin 67 * 68 * Local Motions can include 69 * Up cuu, cuu1, vpa 70 * Down cud, cud1, vpa 71 * Left cul, cul1, hpa, bs, cbt 72 * Right cuf, cuf1, hpa, tab, char moved over 73 */ 74 75 /* This is called _ISMARK2 so it doesn't conflict with _ISMARK1 in wrefresh.c */ 76 77 #define _ISMARK2(x) (mks[(x) / BITSPERBYTE] & (1<<((x) % BITSPERBYTE))) 78 79 #define H_UP -1 80 #define H_DO 1 81 82 static int Newy; 83 static int _homefirst(int, int, int, int), 84 _mvrel(int, int, int, int, int), 85 _mvvert(int, int, int), _mvhor(int, int, int), 86 _mvright(int, int, int), _mvleft(int, int, int); 87 88 int 89 mvcur(int cury, int curx, int newy, int newx) 90 { 91 int hu, /* cost home + relative */ 92 hd, /* cost home-down + relative */ 93 rl, /* cost relative */ 94 cm; /* cost direct cursor motion */ 95 96 /* obvious case */ 97 if (cury == newy && curx == newx) 98 return (OK); 99 100 /* not in the right mode for cursor movement */ 101 if (SP->fl_endwin) 102 return (ERR); 103 104 if (!move_standout_mode && curscr->_attrs && !SP->_mks) 105 _VIDS(A_NORMAL, curscr->_attrs); 106 107 if (!move_insert_mode && SP->phys_irm) 108 _OFFINSERT(); 109 110 Newy = newy; 111 112 /* cost of using cm */ 113 cm = _COST(Cursor_address); 114 115 rl = hd = hu = LARGECOST; 116 117 /* baudrate optimization */ 118 if (cm < LARGECOST && SP->baud >= 2400 && 119 cury >= 0 && cury < curscr->_maxy && 120 curx >= 0 && curx < curscr->_maxx) { 121 if (cursor_down && (newy == (cury + 1)) && 122 ((newx == curx) || (newx == 0 && carriage_return))) { 123 if (newx != curx) 124 _PUTS(carriage_return, 1); 125 _PUTS(cursor_down, 1); 126 goto done; 127 } 128 129 /* fast horizontal move */ 130 if (cury == newy && newx < curx - 4 && newx > curx + 4) { 131 if (newx < curx) 132 rl = _mvleft(curx, newx, FALSE); 133 else 134 rl = _mvright(curx, newx, FALSE); 135 if (rl < cm) { 136 if (newx < curx) 137 rl = _mvleft(curx, newx, TRUE); 138 else 139 rl = _mvright(curx, newx, TRUE); 140 goto done; 141 } 142 } 143 } 144 145 /* cost using relative movements */ 146 if (rl >= LARGECOST && cury >= 0 && cury < curscr->_maxy && 147 curx >= 0 && curx < curscr->_maxx) 148 rl = _mvrel(cury, curx, newy, newx, FALSE); 149 150 /* cost of homing to upper-left corner first */ 151 if (cursor_home) 152 hu = _homefirst(newy, newx, H_UP, FALSE); 153 154 /* cost of homing to lower-left corner first */ 155 if (cursor_to_ll) 156 hd = _homefirst(newy, newx, H_DO, FALSE); 157 158 /* can't do any one of them */ 159 if (cm >= LARGECOST && rl >= LARGECOST && hu >= LARGECOST && 160 hd >= LARGECOST) 161 return (ERR); 162 163 /* do the best one */ 164 if (cm <= rl && cm <= hu && cm <= hd) 165 _PUTS(tparm_p2(cursor_address, newy, newx), 1); 166 else 167 if (rl <= hu && rl <= hd) 168 (void) _mvrel(cury, curx, newy, newx, TRUE); 169 else 170 (void) _homefirst(newy, newx, hu <= hd ? 171 H_UP : H_DO, TRUE); 172 173 done: 174 /* update cursor position */ 175 /*LINTED*/ 176 curscr->_curx = (short) newx; 177 /*LINTED*/ 178 curscr->_cury = (short) newy; 179 180 return (OK); 181 } 182 183 /* Move by homing first. */ 184 185 static int 186 _homefirst(int ny, int nx, int type, int doit) 187 { 188 char *home; 189 int cy, cost; 190 191 if (type == H_UP) { 192 home = cursor_home; 193 cost = _COST(Cursor_home); 194 cy = 0; 195 } else { 196 home = cursor_to_ll; 197 cost = _COST(Cursor_to_ll); 198 cy = curscr->_maxy - 1; 199 } 200 201 if (!home) 202 return (LARGECOST); 203 if (!doit) 204 return (cost + _mvrel(cy, 0, ny, nx, FALSE)); 205 206 _PUTS(home, 1); 207 return (_mvrel(cy, 0, ny, nx, TRUE)); 208 } 209 210 /* Move relatively */ 211 212 static int 213 _mvrel(int cy, int cx, int ny, int nx, int doit) 214 { 215 int cv, ch; 216 217 /* do in this order since _mvhor may need the curscr image */ 218 cv = _mvvert(cy, ny, doit); 219 ch = _mvhor(cx, nx, doit); 220 221 return (cv + ch); 222 } 223 224 /* Move vertically */ 225 226 static int 227 _mvvert(int cy, int ny, int doit) 228 { 229 char *ve; 230 int dy, st_1, st_n, cv; 231 232 if (cy == ny) 233 goto out; 234 235 /* cost of stepwise movement */ 236 if (cy < ny) { 237 dy = ny-cy; 238 st_1 = _COST(Cursor_down) * dy; 239 st_n = _COST(Parm_down_cursor); 240 } else { 241 dy = cy-ny; 242 st_1 = _COST(Cursor_up) * dy; 243 st_n = _COST(Parm_up_cursor); 244 } 245 246 /* cost of using vertical move */ 247 cv = _COST(Row_address); 248 249 /* if calculating cost only */ 250 if (!doit) 251 return ((cv < st_1 && cv < st_n) ? cv : 252 (st_n < st_1) ? st_n : st_1); 253 254 /* do it */ 255 if (cv < st_1 && cv < st_n) 256 _PUTS(tparm_p1(row_address, ny), 1); 257 else 258 if (st_n < st_1) { 259 if (cy < ny) 260 _PUTS(tparm_p1(parm_down_cursor, dy), 1); 261 else 262 _PUTS(tparm_p1(parm_up_cursor, dy), 1); 263 } else { 264 if (cy < ny) 265 ve = cursor_down; 266 else 267 ve = cursor_up; 268 for (; dy > 0; --dy) 269 _PUTS(ve, 1); 270 } 271 272 out: 273 return (0); 274 } 275 276 /* Move horizontally */ 277 278 static int 279 _mvhor(int cx, int nx, int doit) 280 { 281 int st, ch, hl; 282 283 if (cx == nx) 284 goto out; 285 286 /* cost using horizontal move */ 287 ch = _COST(Row_address); 288 289 /* cost doing stepwise */ 290 st = cx < nx ? _mvright(cx, nx, FALSE) : _mvleft(cx, nx, FALSE); 291 292 /* cost homeleft first */ 293 hl = (_COST(Carriage_return) < LARGECOST) ? 294 _COST(Carriage_return) + _mvright(0, nx, FALSE) : LARGECOST; 295 296 if (!doit) 297 return ((ch < st && ch < hl) ? ch : (hl < st ? hl : st)); 298 299 if (ch < st && ch < hl) 300 _PUTS(tparm_p1(column_address, nx), 1); 301 else 302 if (hl < st) { 303 _PUTS(carriage_return, 1); 304 (void) _mvright(0, nx, TRUE); 305 } else { 306 if (cx < nx) 307 (void) _mvright(cx, nx, TRUE); 308 else 309 (void) _mvleft(cx, nx, TRUE); 310 } 311 out: 312 return (0); 313 } 314 315 /* Move right. */ 316 317 static int 318 _mvright(int cx, int nx, int doit) 319 { 320 chtype *scp; 321 char *mks; 322 int nt, tx, x, stcost, iscont; 323 324 if (!cursor_right && !parm_right_cursor) 325 return (LARGECOST); 326 327 scp = curscr->_y[Newy]; 328 mks = magic_cookie_glitch >= 0 ? SP->_mks[Newy] : NULL; 329 330 if (cursor_right) { 331 /* number of tabs used in stepwise movement */ 332 nt = tab ? (nx / TABSIZE - cx / TABSIZE) : 0; 333 tx = (nt > 0) ? (cx / TABSIZE + nt) * TABSIZE : cx; 334 335 /* calculate stepwise cost */ 336 stcost = nt * _COST(Tab); 337 iscont = 0; 338 for (x = tx; x < nx; ++x) { 339 if (iscont == 0 && !ISCBIT(scp[x])) 340 iscont = 1; 341 if ((!ceol_standout_glitch && !mks && 342 _ATTR(scp[x]) == curscr->_attrs) || 343 ceol_standout_glitch || (mks && !_ISMARK2(x))) { 344 if (!ISMBIT(scp[x])) 345 stcost += 1; 346 else if (iscont && !(nx - x == 1 && nx < 347 curscr->_maxx && ISCBIT(scp[nx]))) 348 stcost += 1; 349 else 350 stcost += _COST(Cursor_right); 351 } else 352 stcost += _COST(Cursor_right); 353 } 354 } else 355 stcost = LARGECOST; 356 357 if (!doit) 358 return ((_COST(Parm_right_cursor) < stcost) ? 359 _COST(Parm_right_cursor) : stcost); 360 361 /* actually move */ 362 if (_COST(Parm_right_cursor) < stcost) 363 _PUTS(tparm_p1(parm_right_cursor, nx-cx), 1); 364 else { 365 if (SP->phys_irm) 366 _OFFINSERT(); 367 for (; nt > 0; --nt) 368 _PUTS(tab, 1); 369 iscont = 0; 370 for (x = tx; x < nx; ++x) { 371 if (iscont == 0 && !ISCBIT(scp[x])) 372 iscont = 1; 373 if ((!ceol_standout_glitch && !mks && 374 _ATTR(scp[x]) == curscr->_attrs) || 375 ceol_standout_glitch || (mks && !_ISMARK2(x))) { 376 if (!ISMBIT(scp[x])) 377 (void) _outwch(_CHAR(scp[x])); 378 else if (iscont && !(nx - x == 1 && 379 nx < curscr->_maxx && ISCBIT(scp[nx]))) 380 (void) _outwch(_CHAR(scp[x])); 381 else 382 _PUTS(cursor_right, 1); 383 } else 384 _PUTS(cursor_right, 1); 385 } 386 } 387 388 return (0); 389 } 390 391 /* Move left */ 392 393 static int 394 _mvleft(int cx, int nx, int doit) 395 { 396 int tx, nt, x, stcost; 397 398 if (!cursor_left && !parm_left_cursor) 399 return (LARGECOST); 400 401 if (cursor_left) { 402 /* stepwise cost */ 403 tx = cx; 404 nt = 0; 405 if (back_tab) { 406 /* the TAB position >= nx */ 407 x = (nx % TABSIZE) ? (nx / TABSIZE + 1) * TABSIZE : nx; 408 409 /* # of tabs used and position after using them */ 410 if (x < cx) { 411 nt = (cx / TABSIZE - x / TABSIZE) + 412 ((cx % TABSIZE) ? 1 : 0); 413 tx = x; 414 } 415 } 416 stcost = nt * _COST(Back_tab) + (tx-nx) * _COST(Cursor_left); 417 } else 418 stcost = LARGECOST; 419 420 /* get cost only */ 421 if (!doit) 422 return ((_COST(Parm_left_cursor) < stcost) ? 423 _COST(Parm_left_cursor) : stcost); 424 425 /* doit */ 426 if (_COST(Parm_left_cursor) < stcost) 427 _PUTS(tparm_p1(parm_left_cursor, cx - nx), 1); 428 else { 429 for (; nt > 0; --nt) 430 _PUTS(back_tab, 1); 431 for (; tx > nx; --tx) 432 _PUTS(cursor_left, 1); 433 } 434 435 return (0); 436 } 437