cursor.c revision 2e4f8982
1848b8605Smrg/* $XTermId: cursor.c,v 1.70 2016/05/15 18:35:39 tom Exp $ */ 2848b8605Smrg 3848b8605Smrg/* 4848b8605Smrg * Copyright 2002-2013,2016 by Thomas E. Dickey 5848b8605Smrg * 6848b8605Smrg * All Rights Reserved 7848b8605Smrg * 8848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 9848b8605Smrg * copy of this software and associated documentation files (the 10848b8605Smrg * "Software"), to deal in the Software without restriction, including 11848b8605Smrg * without limitation the rights to use, copy, modify, merge, publish, 12848b8605Smrg * distribute, sublicense, and/or sell copies of the Software, and to 13848b8605Smrg * permit persons to whom the Software is furnished to do so, subject to 14848b8605Smrg * the following conditions: 15848b8605Smrg * 16848b8605Smrg * The above copyright notice and this permission notice shall be included 17848b8605Smrg * in all copies or substantial portions of the Software. 18848b8605Smrg * 19848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21848b8605Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22848b8605Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23848b8605Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24848b8605Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25848b8605Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26848b8605Smrg * 27848b8605Smrg * Except as contained in this notice, the name(s) of the above copyright 28848b8605Smrg * holders shall not be used in advertising or otherwise to promote the 29848b8605Smrg * sale, use or other dealings in this Software without prior written 30848b8605Smrg * authorization. 31848b8605Smrg * 32848b8605Smrg * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 33848b8605Smrg * 34848b8605Smrg * All Rights Reserved 35848b8605Smrg * 36848b8605Smrg * Permission to use, copy, modify, and distribute this software and its 37848b8605Smrg * documentation for any purpose and without fee is hereby granted, 38848b8605Smrg * provided that the above copyright notice appear in all copies and that 39848b8605Smrg * both that copyright notice and this permission notice appear in 40848b8605Smrg * supporting documentation, and that the name of Digital Equipment 41848b8605Smrg * Corporation not be used in advertising or publicity pertaining to 42848b8605Smrg * distribution of the software without specific, written prior permission. 43848b8605Smrg * 44848b8605Smrg * 45848b8605Smrg * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 46848b8605Smrg * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 47848b8605Smrg * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 48848b8605Smrg * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 49848b8605Smrg * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 50848b8605Smrg * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 51848b8605Smrg * SOFTWARE. 52848b8605Smrg */ 53848b8605Smrg 54848b8605Smrg/* cursor.c */ 55848b8605Smrg 56848b8605Smrg#include <xterm.h> 57848b8605Smrg#include <data.h> 58848b8605Smrg#include <menu.h> 59848b8605Smrg 60848b8605Smrg#include <assert.h> 61848b8605Smrg 62848b8605Smrg/* 63848b8605Smrg * Moves the cursor to the specified position, checking for bounds. 64848b8605Smrg * (this includes scrolling regions) 65848b8605Smrg * The origin is considered to be 0, 0 for this procedure. 66848b8605Smrg */ 67848b8605Smrgvoid 68848b8605SmrgCursorSet(TScreen *screen, int row, int col, unsigned flags) 69848b8605Smrg{ 70848b8605Smrg int use_row = row; 71848b8605Smrg int use_col = col; 72848b8605Smrg int max_col = screen->max_col; 73848b8605Smrg int max_row = screen->max_row; 74848b8605Smrg 75848b8605Smrg if (flags & ORIGIN) { 76848b8605Smrg use_col += screen->lft_marg; 77848b8605Smrg max_col = screen->rgt_marg; 78848b8605Smrg } 79848b8605Smrg use_col = (use_col < 0 ? 0 : use_col); 80848b8605Smrg set_cur_col(screen, (use_col <= max_col ? use_col : max_col)); 81848b8605Smrg 82848b8605Smrg if (flags & ORIGIN) { 83848b8605Smrg use_row += screen->top_marg; 84848b8605Smrg max_row = screen->bot_marg; 85848b8605Smrg } 86848b8605Smrg use_row = (use_row < 0 ? 0 : use_row); 87848b8605Smrg set_cur_row(screen, (use_row <= max_row ? use_row : max_row)); 88848b8605Smrg 89848b8605Smrg ResetWrap(screen); 90848b8605Smrg 91848b8605Smrg TRACE(("CursorSet(%d,%d) margins V[%d..%d] H[%d..%d] -> %d,%d %s\n", 92848b8605Smrg row, col, 93848b8605Smrg screen->top_marg, 94848b8605Smrg screen->bot_marg, 95848b8605Smrg screen->lft_marg, 96848b8605Smrg screen->rgt_marg, 97848b8605Smrg screen->cur_row, 98848b8605Smrg screen->cur_col, 99848b8605Smrg ((flags & ORIGIN) ? "origin" : "normal"))); 100848b8605Smrg} 101848b8605Smrg 102848b8605Smrg/* 103848b8605Smrg * moves the cursor left n, no wrap around 104848b8605Smrg */ 105848b8605Smrgvoid 106848b8605SmrgCursorBack(XtermWidget xw, int n) 107848b8605Smrg{ 108848b8605Smrg#define WRAP_MASK (REVERSEWRAP | WRAPAROUND) 109848b8605Smrg TScreen *screen = TScreenOf(xw); 110848b8605Smrg int rev; 111848b8605Smrg int left = ScrnLeftMargin(xw); 112848b8605Smrg int before = screen->cur_col; 113848b8605Smrg 114848b8605Smrg if ((rev = ((xw->flags & WRAP_MASK) == WRAP_MASK)) != 0 115848b8605Smrg && screen->do_wrap) { 116848b8605Smrg n--; 117848b8605Smrg } 118848b8605Smrg 119848b8605Smrg /* if the cursor is already before the left-margin, we have to let it go */ 120848b8605Smrg if (before < left) 121848b8605Smrg left = 0; 122848b8605Smrg 123848b8605Smrg if ((screen->cur_col -= n) < left) { 124848b8605Smrg if (rev) { 125848b8605Smrg int in_row = ScrnRightMargin(xw) - left + 1; 126848b8605Smrg int offset = (in_row * screen->cur_row) + screen->cur_col - left; 127848b8605Smrg if (offset < 0) { 128848b8605Smrg int length = in_row * MaxRows(screen); 129848b8605Smrg offset += ((-offset) / length + 1) * length; 130848b8605Smrg } 131848b8605Smrg set_cur_row(screen, (offset / in_row)); 132848b8605Smrg set_cur_col(screen, (offset % in_row) + left); 133848b8605Smrg do_xevents(); 134848b8605Smrg } else { 135848b8605Smrg set_cur_col(screen, left); 136848b8605Smrg } 137848b8605Smrg } 138848b8605Smrg ResetWrap(screen); 139848b8605Smrg} 140848b8605Smrg 141848b8605Smrg/* 142848b8605Smrg * moves the cursor forward n, no wraparound 143848b8605Smrg */ 144848b8605Smrgvoid 145848b8605SmrgCursorForward(XtermWidget xw, int n) 146848b8605Smrg{ 147848b8605Smrg TScreen *screen = TScreenOf(xw); 148848b8605Smrg#if OPT_DEC_CHRSET 149848b8605Smrg LineData *ld = getLineData(screen, screen->cur_row); 150848b8605Smrg#endif 151848b8605Smrg int next = screen->cur_col + n; 152848b8605Smrg int max; 153848b8605Smrg 154848b8605Smrg if (IsLeftRightMode(xw)) { 155848b8605Smrg max = screen->rgt_marg; 156848b8605Smrg if (screen->cur_col > max) 157848b8605Smrg max = screen->max_col; 158848b8605Smrg } else { 159848b8605Smrg max = LineMaxCol(screen, ld); 160848b8605Smrg } 161848b8605Smrg 162848b8605Smrg if (next > max) 163848b8605Smrg next = max; 164848b8605Smrg 165848b8605Smrg set_cur_col(screen, next); 166848b8605Smrg ResetWrap(screen); 167848b8605Smrg} 168848b8605Smrg 169848b8605Smrg/* 170848b8605Smrg * moves the cursor down n, no scrolling. 171848b8605Smrg * Won't pass bottom margin or bottom of screen. 172848b8605Smrg */ 173848b8605Smrgvoid 174CursorDown(TScreen *screen, int n) 175{ 176 int max; 177 int next = screen->cur_row + n; 178 179 max = (screen->cur_row > screen->bot_marg ? 180 screen->max_row : screen->bot_marg); 181 if (next > max) 182 next = max; 183 if (next > screen->max_row) 184 next = screen->max_row; 185 186 set_cur_row(screen, next); 187 ResetWrap(screen); 188} 189 190/* 191 * moves the cursor up n, no linestarving. 192 * Won't pass top margin or top of screen. 193 */ 194void 195CursorUp(TScreen *screen, int n) 196{ 197 int min; 198 int next = screen->cur_row - n; 199 200 min = ((screen->cur_row < screen->top_marg) 201 ? 0 202 : screen->top_marg); 203 if (next < min) 204 next = min; 205 if (next < 0) 206 next = 0; 207 208 set_cur_row(screen, next); 209 ResetWrap(screen); 210} 211 212/* 213 * Moves cursor down amount lines, scrolls if necessary. 214 * Won't leave scrolling region. No carriage return. 215 */ 216void 217xtermIndex(XtermWidget xw, int amount) 218{ 219 TScreen *screen = TScreenOf(xw); 220 221 /* 222 * indexing when below scrolling region is cursor down. 223 * if cursor high enough, no scrolling necessary. 224 */ 225 if (screen->cur_row > screen->bot_marg 226 || screen->cur_row + amount <= screen->bot_marg 227 || (IsLeftRightMode(xw) 228 && !ScrnIsColInMargins(screen, screen->cur_col))) { 229 CursorDown(screen, amount); 230 } else { 231 int j; 232 CursorDown(screen, j = screen->bot_marg - screen->cur_row); 233 xtermScroll(xw, amount - j); 234 } 235} 236 237/* 238 * Moves cursor up amount lines, reverse scrolls if necessary. 239 * Won't leave scrolling region. No carriage return. 240 */ 241void 242RevIndex(XtermWidget xw, int amount) 243{ 244 TScreen *screen = TScreenOf(xw); 245 246 /* 247 * reverse indexing when above scrolling region is cursor up. 248 * if cursor low enough, no reverse indexing needed 249 */ 250 if (screen->cur_row < screen->top_marg 251 || screen->cur_row - amount >= screen->top_marg 252 || (IsLeftRightMode(xw) 253 && !ScrnIsColInMargins(screen, screen->cur_col))) { 254 CursorUp(screen, amount); 255 } else { 256 RevScroll(xw, amount - (screen->cur_row - screen->top_marg)); 257 CursorUp(screen, screen->cur_row - screen->top_marg); 258 } 259} 260 261/* 262 * Moves Cursor To First Column In Line 263 * (Note: xterm doesn't implement SLH, SLL which would affect use of this) 264 */ 265void 266CarriageReturn(XtermWidget xw) 267{ 268 TScreen *screen = TScreenOf(xw); 269 int left = ScrnLeftMargin(xw); 270 int col; 271 272 if (xw->flags & ORIGIN) { 273 col = left; 274 } else if (screen->cur_col >= left) { 275 col = left; 276 } else { 277 /* 278 * If origin-mode is not active, it is possible to use cursor 279 * addressing outside the margins. In that case we will go to the 280 * first column rather than following the margin. 281 */ 282 col = 0; 283 } 284 285 set_cur_col(screen, col); 286 ResetWrap(screen); 287 do_xevents(); 288} 289 290/* 291 * When resizing the window, if we're showing the alternate screen, we still 292 * have to adjust the saved cursor from the normal screen to account for 293 * shifting of the saved-line region in/out of the viewable window. 294 */ 295void 296AdjustSavedCursor(XtermWidget xw, int adjust) 297{ 298 TScreen *screen = TScreenOf(xw); 299 300 if (screen->whichBuf) { 301 SavedCursor *sc = &screen->sc[0]; 302 303 if (adjust > 0) { 304 TRACE(("AdjustSavedCursor %d -> %d\n", sc->row, sc->row - adjust)); 305 sc->row += adjust; 306 } 307 } 308} 309 310/* 311 * Save Cursor and Attributes 312 */ 313void 314CursorSave(XtermWidget xw) 315{ 316 TScreen *screen = TScreenOf(xw); 317 SavedCursor *sc = &screen->sc[screen->whichBuf]; 318 319 sc->saved = True; 320 sc->row = screen->cur_row; 321 sc->col = screen->cur_col; 322 sc->flags = xw->flags; 323 sc->curgl = screen->curgl; 324 sc->curgr = screen->curgr; 325#if OPT_ISO_COLORS 326 sc->cur_foreground = xw->cur_foreground; 327 sc->cur_background = xw->cur_background; 328 sc->sgr_foreground = xw->sgr_foreground; 329#endif 330 memmove(sc->gsets, screen->gsets, sizeof(screen->gsets)); 331} 332 333/* 334 * We save/restore all visible attributes, plus wrapping, origin mode, and the 335 * selective erase attribute. 336 */ 337#define DECSC_FLAGS (ATTRIBUTES|ORIGIN|WRAPAROUND|PROTECTED) 338 339/* 340 * Restore Cursor and Attributes 341 */ 342void 343CursorRestore(XtermWidget xw) 344{ 345 TScreen *screen = TScreenOf(xw); 346 SavedCursor *sc = &screen->sc[screen->whichBuf]; 347 348 /* Restore the character sets, unless we never did a save-cursor op. 349 * In that case, we'll reset the character sets. 350 */ 351 if (sc->saved) { 352 memmove(screen->gsets, sc->gsets, sizeof(screen->gsets)); 353 screen->curgl = sc->curgl; 354 screen->curgr = sc->curgr; 355 } else { 356 resetCharsets(screen); 357 } 358 359 UIntClr(xw->flags, DECSC_FLAGS); 360 UIntSet(xw->flags, sc->flags & DECSC_FLAGS); 361 CursorSet(screen, 362 ((xw->flags & ORIGIN) 363 ? sc->row - screen->top_marg 364 : sc->row), 365 sc->col, xw->flags); 366 367#if OPT_ISO_COLORS 368 xw->sgr_foreground = sc->sgr_foreground; 369 SGR_Foreground(xw, (xw->flags & FG_COLOR) ? sc->cur_foreground : -1); 370 SGR_Background(xw, (xw->flags & BG_COLOR) ? sc->cur_background : -1); 371#endif 372 update_autowrap(); 373} 374 375/* 376 * Move the cursor to the first column of the n-th next line. 377 */ 378void 379CursorNextLine(XtermWidget xw, int count) 380{ 381 TScreen *screen = TScreenOf(xw); 382 383 CursorDown(screen, count < 1 ? 1 : count); 384 CarriageReturn(xw); 385 do_xevents(); 386} 387 388/* 389 * Move the cursor to the first column of the n-th previous line. 390 */ 391void 392CursorPrevLine(XtermWidget xw, int count) 393{ 394 TScreen *screen = TScreenOf(xw); 395 396 CursorUp(screen, count < 1 ? 1 : count); 397 CarriageReturn(xw); 398 do_xevents(); 399} 400 401/* 402 * Return col/row values which can be passed to CursorSet() preserving the 403 * current col/row, e.g., accounting for DECOM. 404 */ 405int 406CursorCol(XtermWidget xw) 407{ 408 TScreen *screen = TScreenOf(xw); 409 int result = screen->cur_col; 410 if (xw->flags & ORIGIN) { 411 result -= ScrnLeftMargin(xw); 412 if (result < 0) 413 result = 0; 414 } 415 return result; 416} 417 418int 419CursorRow(XtermWidget xw) 420{ 421 TScreen *screen = TScreenOf(xw); 422 int result = screen->cur_row; 423 if (xw->flags & ORIGIN) { 424 result -= screen->top_marg; 425 if (result < 0) 426 result = 0; 427 } 428 return result; 429} 430 431#if OPT_TRACE 432int 433set_cur_row(TScreen *screen, int value) 434{ 435 TRACE(("set_cur_row %d vs %d\n", value, screen ? screen->max_row : -1)); 436 437 assert(screen != 0); 438 assert(value >= 0); 439 assert(value <= screen->max_row); 440 screen->cur_row = value; 441 return value; 442} 443 444int 445set_cur_col(TScreen *screen, int value) 446{ 447 TRACE(("set_cur_col %d vs %d\n", value, screen ? screen->max_col : -1)); 448 449 assert(screen != 0); 450 assert(value >= 0); 451 assert(value <= screen->max_col); 452 screen->cur_col = value; 453 return value; 454} 455#endif /* OPT_TRACE */ 456