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