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