cursor.c revision f2e35a3a
1/* $XTermId: cursor.c,v 1.77 2019/07/12 01:11:59 tom Exp $ */ 2 3/* 4 * Copyright 2002-2018,2019 by Thomas E. Dickey 5 * 6 * All Rights Reserved 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sublicense, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 * Except as contained in this notice, the name(s) of the above copyright 28 * holders shall not be used in advertising or otherwise to promote the 29 * sale, use or other dealings in this Software without prior written 30 * authorization. 31 * 32 * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 33 * 34 * All Rights Reserved 35 * 36 * Permission to use, copy, modify, and distribute this software and its 37 * documentation for any purpose and without fee is hereby granted, 38 * provided that the above copyright notice appear in all copies and that 39 * both that copyright notice and this permission notice appear in 40 * supporting documentation, and that the name of Digital Equipment 41 * Corporation not be used in advertising or publicity pertaining to 42 * distribution of the software without specific, written prior permission. 43 * 44 * 45 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 46 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 47 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 48 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 49 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 50 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 51 * SOFTWARE. 52 */ 53 54/* cursor.c */ 55 56#include <xterm.h> 57#include <data.h> 58#include <menu.h> 59 60#include <assert.h> 61 62/* 63 * Moves the cursor to the specified position, checking for bounds. 64 * (this includes scrolling regions) 65 * The origin is considered to be 0, 0 for this procedure. 66 */ 67void 68CursorSet(TScreen *screen, int row, int col, unsigned flags) 69{ 70 int use_row = row; 71 int use_col = col; 72 int max_col = screen->max_col; 73 int max_row = screen->max_row; 74 75 if (flags & ORIGIN) { 76 use_col += screen->lft_marg; 77 max_col = screen->rgt_marg; 78 } 79 use_col = (use_col < 0 ? 0 : use_col); 80 set_cur_col(screen, (use_col <= max_col ? use_col : max_col)); 81 82 if (flags & ORIGIN) { 83 use_row += screen->top_marg; 84 max_row = screen->bot_marg; 85 } 86 use_row = (use_row < 0 ? 0 : use_row); 87 set_cur_row(screen, (use_row <= max_row ? use_row : max_row)); 88 89 ResetWrap(screen); 90 91 TRACE(("CursorSet(%d,%d) margins V[%d..%d] H[%d..%d] -> %d,%d %s\n", 92 row, col, 93 screen->top_marg, 94 screen->bot_marg, 95 screen->lft_marg, 96 screen->rgt_marg, 97 screen->cur_row, 98 screen->cur_col, 99 ((flags & ORIGIN) ? "origin" : "normal"))); 100} 101 102/* 103 * moves the cursor left n, no wrap around 104 */ 105void 106CursorBack(XtermWidget xw, int n) 107{ 108#define WRAP_MASK (REVERSEWRAP | WRAPAROUND) 109 TScreen *screen = TScreenOf(xw); 110 int rev; 111 int left = ScrnLeftMargin(xw); 112 int before = screen->cur_col; 113 114 if ((rev = ((xw->flags & WRAP_MASK) == WRAP_MASK)) != 0 115 && screen->do_wrap) { 116 n--; 117 } 118 119 /* if the cursor is already before the left-margin, we have to let it go */ 120 if (before < left) 121 left = 0; 122 123 if ((screen->cur_col -= n) < left) { 124 if (rev) { 125 int in_row = ScrnRightMargin(xw) - left + 1; 126 int offset = (in_row * screen->cur_row) + screen->cur_col - left; 127 if ((before == left) && 128 ScrnIsColInMargins(screen, before) && 129 ScrnIsRowInMargins(screen, screen->cur_row) && 130 screen->cur_row == screen->top_marg) { 131 offset = (screen->bot_marg + 1) * in_row - 1; 132 } else if (offset < 0) { 133 int length = in_row * MaxRows(screen); 134 offset += ((-offset) / length + 1) * length; 135 } 136 set_cur_row(screen, (offset / in_row)); 137 set_cur_col(screen, (offset % in_row) + left); 138 do_xevents(xw); 139 } else { 140 set_cur_col(screen, left); 141 } 142 } 143 ResetWrap(screen); 144} 145 146/* 147 * moves the cursor forward n, no wraparound 148 */ 149void 150CursorForward(XtermWidget xw, int n) 151{ 152 TScreen *screen = TScreenOf(xw); 153#if OPT_DEC_CHRSET 154 LineData *ld = getLineData(screen, screen->cur_row); 155#endif 156 int next = screen->cur_col + n; 157 int max; 158 159 if (IsLeftRightMode(xw)) { 160 max = screen->rgt_marg; 161 if (screen->cur_col > max) 162 max = screen->max_col; 163 } else { 164 max = LineMaxCol(screen, ld); 165 } 166 167 if (next > max) 168 next = max; 169 170 set_cur_col(screen, next); 171 ResetWrap(screen); 172} 173 174/* 175 * moves the cursor down n, no scrolling. 176 * Won't pass bottom margin or bottom of screen. 177 */ 178void 179CursorDown(TScreen *screen, int n) 180{ 181 int max; 182 int next = screen->cur_row + n; 183 184 max = (screen->cur_row > screen->bot_marg ? 185 screen->max_row : screen->bot_marg); 186 if (next > max) 187 next = max; 188 if (next > screen->max_row) 189 next = screen->max_row; 190 191 set_cur_row(screen, next); 192 ResetWrap(screen); 193} 194 195/* 196 * moves the cursor up n, no linestarving. 197 * Won't pass top margin or top of screen. 198 */ 199void 200CursorUp(TScreen *screen, int n) 201{ 202 int min; 203 int next = screen->cur_row - n; 204 205 min = ((screen->cur_row < screen->top_marg) 206 ? 0 207 : screen->top_marg); 208 if (next < min) 209 next = min; 210 if (next < 0) 211 next = 0; 212 213 set_cur_row(screen, next); 214 ResetWrap(screen); 215} 216 217/* 218 * Moves cursor down amount lines, scrolls if necessary. 219 * Won't leave scrolling region. No carriage return. 220 */ 221void 222xtermIndex(XtermWidget xw, int amount) 223{ 224 TScreen *screen = TScreenOf(xw); 225 226 /* 227 * indexing when below scrolling region is cursor down. 228 * if cursor high enough, no scrolling necessary. 229 */ 230 if (screen->cur_row > screen->bot_marg 231 || screen->cur_row + amount <= screen->bot_marg 232 || (IsLeftRightMode(xw) 233 && !ScrnIsColInMargins(screen, screen->cur_col))) { 234 CursorDown(screen, amount); 235 } else { 236 int j; 237 CursorDown(screen, j = screen->bot_marg - screen->cur_row); 238 xtermScroll(xw, amount - j); 239 } 240} 241 242/* 243 * Moves cursor up amount lines, reverse scrolls if necessary. 244 * Won't leave scrolling region. No carriage return. 245 */ 246void 247RevIndex(XtermWidget xw, int amount) 248{ 249 TScreen *screen = TScreenOf(xw); 250 251 /* 252 * reverse indexing when above scrolling region is cursor up. 253 * if cursor low enough, no reverse indexing needed 254 */ 255 if (screen->cur_row < screen->top_marg 256 || screen->cur_row - amount >= screen->top_marg 257 || (IsLeftRightMode(xw) 258 && !ScrnIsColInMargins(screen, screen->cur_col))) { 259 CursorUp(screen, amount); 260 } else { 261 RevScroll(xw, amount - (screen->cur_row - screen->top_marg)); 262 CursorUp(screen, screen->cur_row - screen->top_marg); 263 } 264} 265 266/* 267 * Moves Cursor To First Column In Line 268 * (Note: xterm doesn't implement SLH, SLL which would affect use of this) 269 */ 270void 271CarriageReturn(XtermWidget xw) 272{ 273 TScreen *screen = TScreenOf(xw); 274 int left = ScrnLeftMargin(xw); 275 int col; 276 277 if (xw->flags & ORIGIN) { 278 col = left; 279 } else if (screen->cur_col >= left) { 280 col = left; 281 } else { 282 /* 283 * If origin-mode is not active, it is possible to use cursor 284 * addressing outside the margins. In that case we will go to the 285 * first column rather than following the margin. 286 */ 287 col = 0; 288 } 289 290 set_cur_col(screen, col); 291 ResetWrap(screen); 292 do_xevents(xw); 293} 294 295/* 296 * When resizing the window, if we're showing the alternate screen, we still 297 * have to adjust the saved cursor from the normal screen to account for 298 * shifting of the saved-line region in/out of the viewable window. 299 */ 300void 301AdjustSavedCursor(XtermWidget xw, int adjust) 302{ 303 TScreen *screen = TScreenOf(xw); 304 305 if (screen->whichBuf) { 306 SavedCursor *sc = &screen->sc[0]; 307 308 if (adjust > 0) { 309 TRACE(("AdjustSavedCursor %d -> %d\n", sc->row, sc->row - adjust)); 310 sc->row += adjust; 311 } 312 } 313} 314 315/* 316 * Save Cursor and Attributes 317 */ 318void 319CursorSave(XtermWidget xw) 320{ 321 TScreen *screen = TScreenOf(xw); 322 SavedCursor *sc = &screen->sc[screen->whichBuf]; 323 324 sc->saved = True; 325 sc->row = screen->cur_row; 326 sc->col = screen->cur_col; 327 sc->flags = xw->flags; 328 sc->curgl = screen->curgl; 329 sc->curgr = screen->curgr; 330 sc->wrap_flag = screen->do_wrap; 331#if OPT_ISO_COLORS 332 sc->cur_foreground = xw->cur_foreground; 333 sc->cur_background = xw->cur_background; 334 sc->sgr_foreground = xw->sgr_foreground; 335 sc->sgr_38_xcolors = xw->sgr_38_xcolors; 336#endif 337 saveCharsets(screen, sc->gsets); 338} 339 340/* 341 * We save/restore all visible attributes, plus wrapping, origin mode, and the 342 * selective erase attribute. 343 */ 344#define DECSC_FLAGS (ATTRIBUTES|ORIGIN|PROTECTED) 345 346/* 347 * Restore Cursor and Attributes 348 */ 349void 350CursorRestore(XtermWidget xw) 351{ 352 TScreen *screen = TScreenOf(xw); 353 SavedCursor *sc = &screen->sc[screen->whichBuf]; 354 355 /* Restore the character sets, unless we never did a save-cursor op. 356 * In that case, we'll reset the character sets. 357 */ 358 if (sc->saved) { 359 restoreCharsets(screen, sc->gsets); 360 screen->curgl = sc->curgl; 361 screen->curgr = sc->curgr; 362 } else { 363 resetCharsets(screen); 364 } 365 366 UIntClr(xw->flags, DECSC_FLAGS); 367 UIntSet(xw->flags, sc->flags & DECSC_FLAGS); 368 if ((xw->flags & ORIGIN)) { 369 CursorSet(screen, 370 sc->row - screen->top_marg, 371 ((xw->flags & LEFT_RIGHT) 372 ? sc->col - screen->lft_marg 373 : sc->col), 374 xw->flags); 375 } else { 376 CursorSet(screen, sc->row, sc->col, xw->flags); 377 } 378 screen->do_wrap = sc->wrap_flag; /* after CursorSet/ResetWrap */ 379 380#if OPT_ISO_COLORS 381 xw->sgr_foreground = sc->sgr_foreground; 382 xw->sgr_38_xcolors = sc->sgr_38_xcolors; 383 SGR_Foreground(xw, (xw->flags & FG_COLOR) ? sc->cur_foreground : -1); 384 SGR_Background(xw, (xw->flags & BG_COLOR) ? sc->cur_background : -1); 385#endif 386} 387 388/* 389 * Move the cursor to the first column of the n-th next line. 390 */ 391void 392CursorNextLine(XtermWidget xw, int count) 393{ 394 TScreen *screen = TScreenOf(xw); 395 396 CursorDown(screen, count < 1 ? 1 : count); 397 CarriageReturn(xw); 398 do_xevents(xw); 399} 400 401/* 402 * Move the cursor to the first column of the n-th previous line. 403 */ 404void 405CursorPrevLine(XtermWidget xw, int count) 406{ 407 TScreen *screen = TScreenOf(xw); 408 409 CursorUp(screen, count < 1 ? 1 : count); 410 CarriageReturn(xw); 411 do_xevents(xw); 412} 413 414/* 415 * Return col/row values which can be passed to CursorSet() preserving the 416 * current col/row, e.g., accounting for DECOM. 417 */ 418int 419CursorCol(XtermWidget xw) 420{ 421 TScreen *screen = TScreenOf(xw); 422 int result = screen->cur_col; 423 if (xw->flags & ORIGIN) { 424 result -= ScrnLeftMargin(xw); 425 if (result < 0) 426 result = 0; 427 } 428 return result; 429} 430 431int 432CursorRow(XtermWidget xw) 433{ 434 TScreen *screen = TScreenOf(xw); 435 int result = screen->cur_row; 436 if (xw->flags & ORIGIN) { 437 result -= screen->top_marg; 438 if (result < 0) 439 result = 0; 440 } 441 return result; 442} 443 444#if OPT_TRACE 445int 446set_cur_row(TScreen *screen, int value) 447{ 448 TRACE(("set_cur_row %d vs %d\n", value, screen ? screen->max_row : -1)); 449 450 assert(screen != 0); 451 assert(value >= 0); 452 assert(value <= screen->max_row); 453 screen->cur_row = value; 454 return value; 455} 456 457int 458set_cur_col(TScreen *screen, int value) 459{ 460 TRACE(("set_cur_col %d vs %d\n", value, screen ? screen->max_col : -1)); 461 462 assert(screen != 0); 463 assert(value >= 0); 464 assert(value <= screen->max_col); 465 screen->cur_col = value; 466 return value; 467} 468#endif /* OPT_TRACE */ 469