root/foundation-apps/mxterm-maxx/screen.c

Revision 8, 51.7 KB (checked in by emasson, 3 years ago)

initial import for the community edition

Line 
1/* $XTermId: screen.c,v 1.241 2008/04/20 21:07:10 tom Exp $ */
2
3/*
4 * Copyright 1999-2007,2008 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 *
33 * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
34 *
35 *                         All Rights Reserved
36 *
37 * Permission to use, copy, modify, and distribute this software and its
38 * documentation for any purpose and without fee is hereby granted,
39 * provided that the above copyright notice appear in all copies and that
40 * both that copyright notice and this permission notice appear in
41 * supporting documentation, and that the name of Digital Equipment
42 * Corporation not be used in advertising or publicity pertaining to
43 * distribution of the software without specific, written prior permission.
44 *
45 *
46 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
47 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
48 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
49 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
50 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
51 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
52 * SOFTWARE.
53 */
54
55/* screen.c */
56
57#include <stdio.h>
58#include <xterm.h>
59#include <error.h>
60#include <data.h>
61#include <xcharmouse.h>
62#include <xterm_io.h>
63
64#if OPT_WIDE_CHARS
65#include <fontutils.h>
66#include <menu.h>
67#endif
68
69#include <assert.h>
70#include <signal.h>
71
72#define getMinRow(screen) ((xw->flags & ORIGIN) ? (screen)->top_marg : 0)
73#define getMaxRow(screen) ((xw->flags & ORIGIN) ? (screen)->bot_marg : (screen)->max_row)
74#define getMinCol(screen) 0
75#define getMaxCol(screen) ((screen)->max_col)
76
77/*
78 * Allocates memory for a 2-dimensional array of chars and returns a pointer
79 * thereto.  Each line is formed from a set of char arrays, with an index
80 * (i.e., the ScrnBuf type).  The first pointer in the index is reserved for
81 * per-line flags, and does not point to data.
82 *
83 * After the per-line flags, we have a series of pointers to char arrays:  The
84 * first one is the actual character array, the second one is the attributes,
85 * the third is the foreground and background colors, and the fourth denotes
86 * the character set.
87 *
88 * We store it all as pointers, because of alignment considerations, together
89 * with the intention of being able to change the total number of pointers per
90 * row according to whether the user wants color or not.
91 */
92ScrnBuf
93Allocate(int nrow, int ncol, Char ** addr)
94{
95    ScrnBuf base;
96    Char *tmp;
97    int i, j, k;
98    size_t entries = MAX_PTRS * nrow;
99    size_t length = BUF_PTRS * nrow * ncol;
100
101    if ((base = TypeCallocN(ScrnPtr, entries)) == 0)
102        SysError(ERROR_SCALLOC);
103
104    if ((tmp = TypeCallocN(Char, length)) == 0)
105        SysError(ERROR_SCALLOC2);
106
107    *addr = tmp;
108    for (i = k = 0; i < nrow; i++) {
109        base[k] = 0;            /* per-line flags */
110        k += BUF_HEAD;
111        for (j = BUF_HEAD; j < MAX_PTRS; j++) {
112            base[k++] = tmp;
113            tmp += ncol;
114        }
115    }
116
117    return (base);
118}
119
120/*
121 *  This is called when the screen is resized.
122 *  Returns the number of lines the text was moved down (neg for up).
123 *  (Return value only necessary with SouthWestGravity.)
124 */
125static int
126Reallocate(XtermWidget xw,
127           ScrnBuf * sbuf,
128           Char ** sbufaddr,
129           int nrow,
130           int ncol,
131           int oldrow,
132           int oldcol)
133{
134    ScrnBuf base;
135    Char *tmp;
136    int i, j, k, minrows;
137    size_t mincols;
138    Char *oldbuf;
139    int move_down = 0, move_up = 0;
140    size_t entries = MAX_PTRS * nrow;
141    size_t length = BUF_PTRS * nrow * ncol;
142
143    if (sbuf == NULL || *sbuf == NULL) {
144        return 0;
145    }
146
147    oldbuf = *sbufaddr;
148
149    /*
150     * Special case if oldcol == ncol - straight forward realloc and
151     * update of the additional lines in sbuf
152     *
153     * FIXME: this is a good idea, but doesn't seem to be implemented.
154     * -gildea
155     */
156
157    /*
158     * realloc sbuf, the pointers to all the lines.
159     * If the screen shrinks, remove lines off the top of the buffer
160     * if resizeGravity resource says to do so.
161     */
162    if (nrow < oldrow
163        && xw->misc.resizeGravity == SouthWestGravity) {
164        /* Remove lines off the top of the buffer if necessary. */
165        move_up = (oldrow - nrow)
166            - (xw->screen.max_row - xw->screen.cur_row);
167        if (move_up < 0)
168            move_up = 0;
169        /* Overlapping memmove here! */
170        memmove(*sbuf, *sbuf + (move_up * MAX_PTRS),
171                MAX_PTRS * (oldrow - move_up) * sizeof((*sbuf)[0]));
172    }
173    *sbuf = TypeRealloc(ScrnPtr, entries, *sbuf);
174    if (*sbuf == 0)
175        SysError(ERROR_RESIZE);
176    base = *sbuf;
177
178    /*
179     *  create the new buffer space and copy old buffer contents there
180     *  line by line.
181     */
182    if ((tmp = TypeCallocN(Char, length)) == 0)
183        SysError(ERROR_SREALLOC);
184    *sbufaddr = tmp;
185    minrows = (oldrow < nrow) ? oldrow : nrow;
186    mincols = (oldcol < ncol) ? oldcol : ncol;
187    if (nrow > oldrow
188        && xw->misc.resizeGravity == SouthWestGravity) {
189        /* move data down to bottom of expanded screen */
190        move_down = Min(nrow - oldrow, xw->screen.savedlines);
191        tmp += (ncol * move_down * BUF_PTRS);
192    }
193
194    for (i = k = 0; i < minrows; i++) {
195        k += BUF_HEAD;
196        for (j = BUF_HEAD; j < MAX_PTRS; j++) {
197            memcpy(tmp, base[k++], mincols);
198            tmp += ncol;
199        }
200    }
201
202    /*
203     * update the pointers in sbuf
204     */
205    for (i = k = 0, tmp = *sbufaddr; i < nrow; i++) {
206        for (j = 0; j < BUF_HEAD; j++)
207            base[k++] = 0;
208        for (j = BUF_HEAD; j < MAX_PTRS; j++) {
209            base[k++] = tmp;
210            tmp += ncol;
211        }
212    }
213
214    /* Now free the old buffer */
215    free(oldbuf);
216
217    return move_down ? move_down : -move_up;    /* convert to rows */
218}
219
220#if OPT_WIDE_CHARS
221#if 0
222static void
223dump_screen(const char *tag,
224            XtermWidget xw,
225            ScrnBuf sbuf,
226            Char * sbufaddr,
227            unsigned nrow,
228            unsigned ncol)
229{
230    unsigned y, x;
231
232    TRACE(("DUMP %s, ptrs %d\n", tag, xw->num_ptrs));
233    TRACE(("  sbuf      %p\n", sbuf));
234    TRACE(("  sbufaddr  %p\n", sbufaddr));
235    TRACE(("  nrow      %d\n", nrow));
236    TRACE(("  ncol      %d\n", ncol));
237
238    for (y = 0; y < nrow; ++y) {
239        ScrnPtr ptr = BUF_CHARS(sbuf, y);
240        TRACE(("%3d:%p:", y, ptr));
241        for (x = 0; x < ncol; ++x) {
242            Char c = ptr[x];
243            if (c == 0)
244                c = '~';
245            TRACE(("%c", c));
246        }
247        TRACE(("\n"));
248    }
249}
250#else
251#define dump_screen(tag, xw, sbuf, sbufaddr, nrow, ncol)        /* nothing */
252#endif
253
254/*
255 * This function reallocates memory if changing the number of Buf offsets.
256 * The code is based on Reallocate().
257 */
258static void
259ReallocateBufOffsets(XtermWidget xw,
260                     ScrnBuf * sbuf,
261                     Char ** sbufaddr,
262                     unsigned nrow,
263                     unsigned ncol,
264                     size_t new_max_offsets)
265{
266    unsigned i;
267    int j, k;
268    ScrnBuf base;
269    Char *oldbuf, *tmp;
270    size_t entries, length;
271    /*
272     * As there are 2 buffers (allbuf, altbuf), we cannot change num_ptrs in
273     * this function.  However MAX_PTRS and BUF_PTRS depend on num_ptrs so
274     * change it now and restore the value when done.
275     */
276    int old_max_ptrs = MAX_PTRS;
277
278    assert(nrow != 0);
279    assert(ncol != 0);
280    assert(new_max_offsets != 0);
281
282    dump_screen("before", xw, *sbuf, *sbufaddr, nrow, ncol);
283
284    xw->num_ptrs = new_max_offsets;
285
286    entries = MAX_PTRS * nrow;
287    length = BUF_PTRS * nrow * ncol;
288    oldbuf = *sbufaddr;
289
290    *sbuf = TypeRealloc(ScrnPtr, entries, *sbuf);
291    if (*sbuf == 0)
292        SysError(ERROR_RESIZE);
293    base = *sbuf;
294
295    if ((tmp = TypeCallocN(Char, length)) == 0)
296        SysError(ERROR_SREALLOC);
297    *sbufaddr = tmp;
298
299    for (i = k = 0; i < nrow; i++) {
300        k += BUF_HEAD;
301        for (j = BUF_HEAD; j < old_max_ptrs; j++) {
302            memcpy(tmp, base[k++], ncol);
303            tmp += ncol;
304        }
305        tmp += ncol * (new_max_offsets - old_max_ptrs);
306    }
307
308    /*
309     * update the pointers in sbuf
310     */
311    for (i = k = 0, tmp = *sbufaddr; i < nrow; i++) {
312        for (j = 0; j < BUF_HEAD; j++)
313            base[k++] = 0;
314        for (j = BUF_HEAD; j < MAX_PTRS; j++) {
315            base[k++] = tmp;
316            tmp += ncol;
317        }
318    }
319
320    /* Now free the old buffer and restore num_ptrs */
321    free(oldbuf);
322    dump_screen("after", xw, *sbuf, *sbufaddr, nrow, ncol);
323
324    xw->num_ptrs = old_max_ptrs;
325}
326
327/*
328 * This function dynamically adds support for wide-characters.
329 */
330void
331ChangeToWide(XtermWidget xw)
332{
333    TScreen *screen = &(xw->screen);
334    unsigned new_bufoffset = OFF_FINAL + (screen->max_combining * 2);
335    int savelines = screen->scrollWidget ? screen->savelines : 0;
336
337    if (screen->wide_chars)
338        return;
339
340    TRACE(("ChangeToWide\n"));
341    if (xtermLoadWideFonts(xw, True)) {
342        if (savelines < 0)
343            savelines = 0;
344
345        /*
346         * If we're displaying the alternate screen, switch the pointers back
347         * temporarily so ReallocateBufOffsets() will operate on the proper
348         * data in altbuf.
349         */
350        if (screen->alternate)
351            SwitchBufPtrs(screen);
352
353        ReallocateBufOffsets(xw,
354                             &screen->allbuf, &screen->sbuf_address,
355                             (unsigned) (MaxRows(screen) + savelines),
356                             (unsigned) MaxCols(screen),
357                             new_bufoffset);
358        if (screen->altbuf) {
359            ReallocateBufOffsets(xw,
360                                 &screen->altbuf, &screen->abuf_address,
361                                 (unsigned) MaxRows(screen),
362                                 (unsigned) MaxCols(screen),
363                                 new_bufoffset);
364        }
365
366        screen->wide_chars = True;
367        xw->num_ptrs = new_bufoffset;
368        screen->visbuf = &screen->allbuf[MAX_PTRS * savelines];
369
370        /*
371         * Switch the pointers back before we start painting on the screen.
372         */
373        if (screen->alternate)
374            SwitchBufPtrs(screen);
375
376        update_font_utf8_mode();
377        SetVTFont(xw, screen->menu_font_number, True, NULL);
378    }
379    TRACE(("...ChangeToWide\n"));
380}
381#endif
382
383/*
384 * Clear cells, no side-effects.
385 */
386void
387ClearCells(XtermWidget xw, int flags, unsigned len, int row, int col)
388{
389    if (len != 0) {
390        TScreen *screen = &(xw->screen);
391        flags |= TERM_COLOR_FLAGS(xw);
392
393        memset(SCRN_BUF_CHARS(screen, row) + col, ' ', len);
394        memset(SCRN_BUF_ATTRS(screen, row) + col, flags, len);
395
396        if_OPT_EXT_COLORS(screen, {
397            memset(SCRN_BUF_FGRND(screen, row) + col,
398                   xw->sgr_foreground, len);
399            memset(SCRN_BUF_BGRND(screen, row) + col,
400                   xw->cur_background, len);
401        });
402        if_OPT_ISO_TRADITIONAL_COLORS(screen, {
403            memset(SCRN_BUF_COLOR(screen, row) + col,
404                   (int) xtermColorPair(xw), len);
405        });
406        if_OPT_DEC_CHRSET({
407            memset(SCRN_BUF_CSETS(screen, row) + col,
408                   curXtermChrSet(xw, row), len);
409        });
410        if_OPT_WIDE_CHARS(screen, {
411            int off;
412            for (off = OFF_WIDEC; off < MAX_PTRS; ++off) {
413                memset(SCREEN_PTR(screen, row, off) + col, 0, len);
414            }
415        });
416    }
417}
418
419/*
420 * Clear data in the screen-structure (no I/O).
421 * Check for wide-character damage as well, clearing the damaged cells.
422 */
423void
424ScrnClearCells(XtermWidget xw, int row, int col, unsigned len)
425{
426#if OPT_WIDE_CHARS
427    TScreen *screen = &(xw->screen);
428#endif
429    int flags = 0;
430
431    if_OPT_WIDE_CHARS(screen, {
432        int kl;
433        int kr;
434        if (DamagedCells(screen, len, &kl, &kr, INX2ROW(screen, row), col)
435            && kr >= kl) {
436            ClearCells(xw, flags, (unsigned) (kr - kl + 1), row, kl);
437        }
438    });
439    ClearCells(xw, flags, len, row, col);
440}
441
442/*
443 * Disown the selection and repaint the area that is highlighted so it is no
444 * longer highlighted.
445 */
446void
447ScrnDisownSelection(XtermWidget xw)
448{
449    if (ScrnHaveSelection(&(xw->screen))) {
450        if (xw->screen.keepSelection) {
451            UnhiliteSelection(xw);
452        } else {
453            DisownSelection(xw);
454        }
455    }
456}
457
458/*
459 * Writes str into buf at screen's current row and column.  Characters are set
460 * to match flags.
461 */
462void
463ScrnWriteText(XtermWidget xw,
464              PAIRED_CHARS(Char * str, Char * str2),
465              unsigned flags,
466              unsigned cur_fg_bg,
467              unsigned length)
468{
469    TScreen *screen = &(xw->screen);
470#if OPT_ISO_COLORS
471#if OPT_EXT_COLORS
472    Char *fbf = 0;
473    Char *fbb = 0;
474#else
475    Char *fb = 0;
476#endif
477#endif
478#if OPT_DEC_CHRSET
479    Char *cb = 0;
480#endif
481    Char *attrs;
482    int avail = MaxCols(screen) - screen->cur_col;
483    Char *chars;
484#if OPT_WIDE_CHARS
485    Char starcol1, starcol2;
486#endif
487    unsigned real_width = visual_width(PAIRED_CHARS(str, str2), length);
488
489    (void) cur_fg_bg;
490
491    if (avail <= 0)
492        return;
493    if (length > (unsigned) avail)
494        length = avail;
495    if (length == 0 || real_width == 0)
496        return;
497
498    chars = SCRN_BUF_CHARS(screen, screen->cur_row) + screen->cur_col;
499    attrs = SCRN_BUF_ATTRS(screen, screen->cur_row) + screen->cur_col;
500
501    if_OPT_EXT_COLORS(screen, {
502        fbf = SCRN_BUF_FGRND(screen, screen->cur_row) + screen->cur_col;
503        fbb = SCRN_BUF_BGRND(screen, screen->cur_row) + screen->cur_col;
504    });
505    if_OPT_ISO_TRADITIONAL_COLORS(screen, {
506        fb = SCRN_BUF_COLOR(screen, screen->cur_row) + screen->cur_col;
507    });
508    if_OPT_DEC_CHRSET({
509        cb = SCRN_BUF_CSETS(screen, screen->cur_row) + screen->cur_col;
510    });
511
512#if OPT_WIDE_CHARS
513    starcol1 = *chars;
514    starcol2 = chars[length - 1];
515#endif
516
517    /* write blanks if we're writing invisible text */
518    if (flags & INVISIBLE) {
519        memset(chars, ' ', length);
520    } else {
521        memcpy(chars, str, length);     /* This can stand for the present. If it
522                                           is wrong, we will scribble over it */
523    }
524
525#if OPT_BLINK_TEXT
526    if ((flags & BLINK) && !(screen->blink_as_bold)) {
527        ScrnSetBlinked(screen, screen->cur_row);
528    }
529#endif
530
531#define ERROR_1 0x20
532#define ERROR_2 0x00
533    if_OPT_WIDE_CHARS(screen, {
534
535        Char *char2;
536
537        if (real_width != length) {
538            Char *char1 = chars;
539            char2 = SCRN_BUF_WIDEC(screen, screen->cur_row);
540            char2 += screen->cur_col;
541            if (screen->cur_col && starcol1 == HIDDEN_LO && *char2 == HIDDEN_HI
542                && iswide(PACK_PAIR(char1, char2, -1))) {
543                char1[-1] = ERROR_1;
544                char2[-1] = ERROR_2;
545            }
546            /* if we are overwriting the right hand half of a
547               wide character, make the other half vanish */
548            while (length) {
549                int ch = PACK_PAIR(str, str2, 0);
550
551                *char1 = *str;
552                char1++;
553                str++;
554
555                if (str2) {
556                    *char2 = *str2;
557                    str2++;
558                } else
559                    *char2 = 0;
560                char2++;
561                length--;
562
563                if (iswide(ch)) {
564                    *char1 = HIDDEN_LO;
565                    *char2 = HIDDEN_HI;
566                    char1++;
567                    char2++;
568                }
569            }
570
571            if (*char1 == HIDDEN_LO
572                && *char2 == HIDDEN_HI
573                && char1[-1] == HIDDEN_LO
574                && char2[-1] == HIDDEN_HI) {
575                *char1 = ERROR_1;
576                *char2 = ERROR_2;
577            }
578            /* if we are overwriting the left hand half of a
579               wide character, make the other half vanish */
580        } else {
581
582            if ((char2 = SCRN_BUF_WIDEC(screen, screen->cur_row)) != 0) {
583                char2 += screen->cur_col;
584                if (screen->cur_col && starcol1 == HIDDEN_LO && *char2 == HIDDEN_HI
585                    && iswide(PACK_PAIR(chars, char2, -1))) {
586                    chars[-1] = ERROR_1;
587                    char2[-1] = ERROR_2;
588                }
589                /* if we are overwriting the right hand half of a
590                   wide character, make the other half vanish */
591                if (chars[length] == HIDDEN_LO && char2[length] == HIDDEN_HI &&
592                    iswide(PACK_PAIR(chars, char2, length - 1))) {
593                    chars[length] = ERROR_1;
594                    char2[length] = ERROR_2;
595                }
596                /* if we are overwriting the left hand half of a
597                   wide character, make the other half vanish */
598                if ((flags & INVISIBLE) || (str2 == 0))
599                    memset(char2, 0, length);
600                else
601                    memcpy(char2, str2, length);
602            }
603        }
604    });
605
606    flags &= ATTRIBUTES;
607    flags |= CHARDRAWN;
608    memset(attrs, (Char) flags, real_width);
609
610    if_OPT_WIDE_CHARS(screen, {
611        int off;
612        for (off = OFF_FINAL; off < MAX_PTRS; ++off) {
613            memset(SCREEN_PTR(screen,
614                              screen->cur_row,
615                              off) + screen->cur_col,
616                   0, real_width);
617        }
618    });
619    if_OPT_EXT_COLORS(screen, {
620        memset(fbf, (int) ExtractForeground(cur_fg_bg), real_width);
621        memset(fbb, (int) ExtractBackground(cur_fg_bg), real_width);
622    });
623    if_OPT_ISO_TRADITIONAL_COLORS(screen, {
624        memset(fb, (int) cur_fg_bg, real_width);
625    });
626    if_OPT_DEC_CHRSET({
627        memset(cb, curXtermChrSet(xw, screen->cur_row), real_width);
628    });
629
630    if_OPT_WIDE_CHARS(screen, {
631        screen->last_written_col = screen->cur_col + real_width - 1;
632        screen->last_written_row = screen->cur_row;
633    });
634
635    if_OPT_XMC_GLITCH(screen, {
636        Resolve_XMC(xw);
637    });
638}
639
640/*
641 * Saves pointers to the n lines beginning at sb + where, and clears the lines
642 */
643static void
644ScrnClearLines(XtermWidget xw, ScrnBuf sb, int where, unsigned n, unsigned size)
645{
646    TScreen *screen = &(xw->screen);
647    int i, j;
648    size_t len = ScrnPointers(screen, n);
649    int last = (n * MAX_PTRS);
650
651    TRACE(("ScrnClearLines(where %d, n %d, size %d)\n", where, n, size));
652
653    assert(n != 0);
654    assert(size != 0);
655
656    /* save n lines at where */
657    memcpy((char *) screen->save_ptr,
658           (char *) &sb[MAX_PTRS * where],
659           len);
660
661    /* clear contents of old rows */
662    if (TERM_COLOR_FLAGS(xw)) {
663        int flags = TERM_COLOR_FLAGS(xw);
664        for (i = 0; i < last; i += MAX_PTRS) {
665            for (j = 0; j < MAX_PTRS; j++) {
666                if (j < BUF_HEAD)
667                    screen->save_ptr[i + j] = 0;
668                else if (j == OFF_ATTRS)
669                    memset(screen->save_ptr[i + j], flags, size);
670#if OPT_ISO_COLORS
671#if OPT_EXT_COLORS
672                else if (j == OFF_FGRND)
673                    memset(screen->save_ptr[i + j], xw->sgr_foreground, size);
674                else if (j == OFF_BGRND)
675                    memset(screen->save_ptr[i + j], xw->cur_background, size);
676#else
677                else if (j == OFF_COLOR)
678                    memset(screen->save_ptr[i + j], (int)
679                           xtermColorPair(xw), size);
680#endif
681#endif
682                else
683                    bzero(screen->save_ptr[i + j], size);
684            }
685        }
686    } else {
687        for (i = 0; i < last; i += MAX_PTRS) {
688            for (j = 0; j < BUF_HEAD; j++)
689                screen->save_ptr[i + j] = 0;
690            for (j = BUF_HEAD; j < MAX_PTRS; j++)
691                bzero(screen->save_ptr[i + j], size);
692        }
693    }
694}
695
696size_t
697ScrnPointers(TScreen * screen, size_t len)
698{
699    len *= MAX_PTRS;
700
701    if (len > screen->save_len) {
702        if (screen->save_len)
703            screen->save_ptr = TypeRealloc(ScrnPtr, len, screen->save_ptr);
704        else
705            screen->save_ptr = TypeMallocN(ScrnPtr, len);
706        screen->save_len = len;
707        if (screen->save_ptr == 0)
708            SysError(ERROR_SAVE_PTR);
709    }
710    return len * sizeof(ScrnPtr);
711}
712
713/*
714 * Inserts n blank lines at sb + where, treating last as a bottom margin.
715 * size is the size of each entry in sb.
716 */
717void
718ScrnInsertLine(XtermWidget xw, ScrnBuf sb, int last, int where,
719               unsigned n, unsigned size)
720{
721    TScreen *screen = &(xw->screen);
722    size_t len = ScrnPointers(screen, n);
723
724    assert(where >= 0);
725    assert(last >= (int) n);
726    assert(last >= where);
727
728    assert(n != 0);
729    assert(size != 0);
730    assert(MAX_PTRS > 0);
731
732    /* save n lines at bottom */
733    ScrnClearLines(xw, sb, (last -= n - 1), n, size);
734
735    /*
736     * WARNING, overlapping copy operation.  Move down lines (pointers).
737     *
738     *   +----|---------|--------+
739     *
740     * is copied in the array to:
741     *
742     *   +--------|---------|----+
743     */
744    assert(last >= where);
745    memmove((char *) &sb[MAX_PTRS * (where + n)],
746            (char *) &sb[MAX_PTRS * where],
747            MAX_PTRS * sizeof(char *) * (last - where));
748
749    /* reuse storage for new lines at where */
750    memcpy((char *) &sb[MAX_PTRS * where],
751           (char *) screen->save_ptr,
752           len);
753}
754
755/*
756 * Deletes n lines at sb + where, treating last as a bottom margin.
757 * size is the size of each entry in sb.
758 */
759void
760ScrnDeleteLine(XtermWidget xw, ScrnBuf sb, int last, int where,
761               unsigned n, unsigned size)
762{
763    TScreen *screen = &(xw->screen);
764
765    assert(where >= 0);
766    assert(last >= where + (int) n - 1);
767
768    assert(n != 0);
769    assert(size != 0);
770    assert(MAX_PTRS > 0);
771
772    ScrnClearLines(xw, sb, where, n, size);
773
774    /* move up lines */
775    memmove((char *) &sb[MAX_PTRS * where],
776            (char *) &sb[MAX_PTRS * (where + n)],
777            MAX_PTRS * sizeof(char *) * ((last -= n - 1) - where));
778
779    /* reuse storage for new bottom lines */
780    memcpy((char *) &sb[MAX_PTRS * last],
781           (char *) screen->save_ptr,
782           MAX_PTRS * sizeof(char *) * n);
783}
784
785/*
786 * Inserts n blanks in screen at current row, col.  Size is the size of each
787 * row.
788 */
789void
790ScrnInsertChar(XtermWidget xw, unsigned n)
791{
792#define Target (data + col + n)
793#define Source (data + col)
794
795    TScreen *screen = &(xw->screen);
796    ScrnBuf sb = screen->visbuf;
797    int last = MaxCols(screen);
798    int row = screen->cur_row;
799    int col = screen->cur_col;
800    Char *data;
801    size_t nbytes;
802
803    if (last <= (int) (col + n)) {
804        if (last <= col)
805            return;
806        n = last - col;
807    }
808    nbytes = (last - (col + n));
809
810    assert(screen->cur_col >= 0);
811    assert(screen->cur_row >= 0);
812    assert(n > 0);
813    assert(last > (int) n);
814
815    if_OPT_WIDE_CHARS(screen, {
816        int xx = INX2ROW(screen, screen->cur_row);
817        int kl;
818        int kr = screen->cur_col;
819        if (DamagedCells(screen, n, &kl, (int *) 0, xx, kr) && kr > kl) {
820            ClearCells(xw, 0, (unsigned) (kr - kl + 1), row, kl);
821        }
822        kr = screen->max_col - n + 1;
823        if (DamagedCells(screen, n, &kl, (int *) 0, xx, kr) && kr > kl) {
824            ClearCells(xw, 0, (unsigned) (kr - kl + 1), row, kl);
825        }
826    });
827
828    data = BUF_CHARS(sb, row);
829    memmove(Target, Source, nbytes);
830
831    data = BUF_ATTRS(sb, row);
832    memmove(Target, Source, nbytes);
833
834    if_OPT_EXT_COLORS(screen, {
835        data = BUF_FGRND(sb, row);
836        memmove(Target, Source, nbytes);
837        data = BUF_BGRND(sb, row);
838        memmove(Target, Source, nbytes);
839    });
840    if_OPT_ISO_TRADITIONAL_COLORS(screen, {
841        data = BUF_COLOR(sb, row);
842        memmove(Target, Source, nbytes);
843    });
844    if_OPT_DEC_CHRSET({
845        data = BUF_CSETS(sb, row);
846        memmove(Target, Source, nbytes);
847    });
848    if_OPT_WIDE_CHARS(screen, {
849        int off;
850        for (off = OFF_WIDEC; off < MAX_PTRS; ++off) {
851            data = BUFFER_PTR(sb, row, off);
852            memmove(Target, Source, nbytes);
853        }
854    });
855    ClearCells(xw, CHARDRAWN, n, row, col);
856
857#undef Source
858#undef Target
859}
860
861/*
862 * Deletes n characters at current row, col.
863 */
864void
865ScrnDeleteChar(XtermWidget xw, unsigned n)
866{
867#define Target (data + col)
868#define Source (data + col + n)
869
870    TScreen *screen = &(xw->screen);
871    ScrnBuf sb = screen->visbuf;
872    int last = MaxCols(screen);
873    int row = screen->cur_row;
874    int col = screen->cur_col;
875    Char *data;
876    size_t nbytes;
877
878    if (last <= (int) (col + n)) {
879        if (last <= col)
880            return;
881        n = last - col;
882    }
883    nbytes = (last - (col + n));
884
885    assert(screen->cur_col >= 0);
886    assert(screen->cur_row >= 0);
887    assert(n > 0);
888    assert(last > (int) n);
889
890    if_OPT_WIDE_CHARS(screen, {
891        int kl;
892        int kr;
893        if (DamagedCells(screen, n, &kl, &kr,
894                         INX2ROW(screen, screen->cur_row),
895                         screen->cur_col))
896            ClearCells(xw, 0, (unsigned) (kr - kl + 1), row, kl);
897    });
898
899    data = BUF_CHARS(sb, row);
900    memmove(Target, Source, nbytes);
901
902    data = BUF_ATTRS(sb, row);
903    memmove(Target, Source, nbytes);
904
905    if_OPT_EXT_COLORS(screen, {
906        data = BUF_FGRND(sb, row);
907        memmove(Target, Source, nbytes);
908        data = BUF_BGRND(sb, row);
909        memmove(Target, Source, nbytes);
910    });
911    if_OPT_ISO_TRADITIONAL_COLORS(screen, {
912        data = BUF_COLOR(sb, row);
913        memmove(Target, Source, nbytes);
914    });
915    if_OPT_DEC_CHRSET({
916        data = BUF_CSETS(sb, row);
917        memmove(Target, Source, nbytes);
918    });
919    if_OPT_WIDE_CHARS(screen, {
920        int off;
921        for (off = OFF_WIDEC; off < MAX_PTRS; ++off) {
922            data = BUFFER_PTR(sb, row, off);
923            memmove(Target, Source, nbytes);
924        }
925    });
926    ClearCells(xw, 0, n, row, (int) (last - n));
927    ScrnClrWrapped(screen, row);
928
929#undef Source
930#undef Target
931}
932
933/*
934 * Repaints the area enclosed by the parameters.
935 * Requires: (toprow, leftcol), (toprow + nrows, leftcol + ncols) are
936 *           coordinates of characters in screen;
937 *           nrows and ncols positive.
938 *           all dimensions are based on single-characters.
939 */
940void
941ScrnRefresh(XtermWidget xw,
942            int toprow,
943            int leftcol,
944            int nrows,
945            int ncols,
946            Bool force)         /* ... leading/trailing spaces */
947{
948    TScreen *screen = &(xw->screen);
949    int y = toprow * FontHeight(screen) + screen->border;
950    int row;
951    int maxrow = toprow + nrows - 1;
952    int scrollamt = screen->scroll_amt;
953    int max = screen->max_row;
954    int gc_changes = 0;
955#ifdef __CYGWIN__
956    static char first_time = 1;
957#endif
958    static int recurse = 0;
959
960    TRACE(("ScrnRefresh (%d,%d) - (%d,%d)%s\n",
961           toprow, leftcol,
962           nrows, ncols,
963           force ? " force" : ""));
964
965    if (screen->cursorp.col >= leftcol
966        && screen->cursorp.col <= (leftcol + ncols - 1)
967        && screen->cursorp.row >= ROW2INX(screen, toprow)
968        && screen->cursorp.row <= ROW2INX(screen, maxrow))
969        screen->cursor_state = OFF;
970
971    for (row = toprow; row <= maxrow; y += FontHeight(screen), row++) {
972#if OPT_ISO_COLORS
973#if OPT_EXT_COLORS
974        Char *fbf = 0;
975        Char *fbb = 0;
976#define ColorOf(col) (unsigned) ((fbf[col] << 8) | fbb[col])
977#else
978        Char *fb = 0;
979#define ColorOf(col) (unsigned) (fb[col])
980#endif
981#endif
982#if OPT_DEC_CHRSET
983        Char *cb = 0;
984#endif
985#if OPT_WIDE_CHARS
986        int wideness = 0;
987        Char *widec = 0;
988#define WIDEC_PTR(cell) widec ? &widec[cell] : 0
989#define BLANK_CEL(cell) ((chars[cell] == ' ') && (widec == 0 || widec[cell] == 0))
990#else
991#define BLANK_CEL(cell) (chars[cell] == ' ')
992#endif
993        Char cs = 0;
994        Char *chars;
995        Char *attrs;
996        int col = leftcol;
997        int maxcol = leftcol + ncols - 1;
998        int hi_col = maxcol;
999        int lastind;
1000        unsigned flags;
1001        unsigned test;
1002        unsigned fg_bg = 0, fg = 0, bg = 0;
1003        int x;
1004        GC gc;
1005        Bool hilite;
1006
1007        (void) fg;
1008        (void) bg;
1009
1010        if (row < screen->top_marg || row > screen->bot_marg)
1011            lastind = row;
1012        else
1013            lastind = row - scrollamt;
1014
1015        TRACE(("ScrnRefresh row=%d lastind=%d/%d\n", row, lastind, max));
1016        if (lastind < 0 || lastind > max)
1017            continue;
1018
1019        chars = SCRN_BUF_CHARS(screen, ROW2INX(screen, lastind));
1020        attrs = SCRN_BUF_ATTRS(screen, ROW2INX(screen, lastind));
1021
1022        if_OPT_DEC_CHRSET({
1023            cb = SCRN_BUF_CSETS(screen, ROW2INX(screen, lastind));
1024        });
1025
1026        if_OPT_WIDE_CHARS(screen, {
1027            widec = SCRN_BUF_WIDEC(screen, ROW2INX(screen, lastind));
1028        });
1029
1030        if_OPT_WIDE_CHARS(screen, {
1031            /* This fixes an infinite recursion bug, that leads
1032               to display anomalies. It seems to be related to
1033               problems with the selection. */
1034            if (recurse < 3) {
1035                /* adjust to redraw all of a widechar if we just wanted
1036                   to draw the right hand half */
1037                if (leftcol > 0 &&
1038                    (PACK_PAIR(chars, widec, leftcol)) == HIDDEN_CHAR &&
1039                    iswide(PACK_PAIR(chars, widec, leftcol - 1))) {
1040                    leftcol--;
1041                    ncols++;
1042                    col = leftcol;
1043                }
1044            } else {
1045                fprintf(stderr, "This should not happen. Why is it so?\n");
1046            }
1047        });
1048
1049        if (row < screen->startH.row || row > screen->endH.row ||
1050            (row == screen->startH.row && maxcol < screen->startH.col) ||
1051            (row == screen->endH.row && col >= screen->endH.col)) {
1052#if OPT_DEC_CHRSET
1053            /*
1054             * Temporarily change dimensions to double-sized characters so
1055             * we can reuse the recursion on this function.
1056             */
1057            if (CSET_DOUBLE(*cb)) {
1058                col /= 2;
1059                maxcol /= 2;
1060            }
1061#endif
1062            /*
1063             * If row does not intersect selection; don't hilite blanks.
1064             */
1065            if (!force) {
1066                while (col <= maxcol && (attrs[col] & ~BOLD) == 0 &&
1067                       BLANK_CEL(col))
1068                    col++;
1069
1070                while (col <= maxcol && (attrs[maxcol] & ~BOLD) == 0 &&
1071                       BLANK_CEL(maxcol))
1072                    maxcol--;
1073            }
1074#if OPT_DEC_CHRSET
1075            if (CSET_DOUBLE(*cb)) {
1076                col *= 2;
1077                maxcol *= 2;
1078            }
1079#endif
1080            hilite = False;
1081        } else {
1082            /* row intersects selection; split into pieces of single type */
1083            if (row == screen->startH.row && col < screen->startH.col) {
1084                recurse++;
1085                ScrnRefresh(xw, row, col, 1, screen->startH.col - col,
1086                            force);
1087                col = screen->startH.col;
1088            }
1089            if (row == screen->endH.row && maxcol >= screen->endH.col) {
1090                recurse++;
1091                ScrnRefresh(xw, row, screen->endH.col, 1,
1092                            maxcol - screen->endH.col + 1, force);
1093                maxcol = screen->endH.col - 1;
1094            }
1095
1096            /*
1097             * If we're highlighting because the user is doing cut/paste,
1098             * trim the trailing blanks from the highlighted region so we're
1099             * showing the actual extent of the text that'll be cut.  If
1100             * we're selecting a blank line, we'll highlight one column
1101             * anyway.
1102             *
1103             * We don't do this if the mouse-hilite mode is set because that
1104             * would be too confusing.
1105             *
1106             * The default if the highlightSelection resource isn't set will
1107             * highlight the whole width of the terminal, which is easy to
1108             * see, but harder to use (because trailing blanks aren't as
1109             * apparent).
1110             */
1111            if (screen->highlight_selection
1112                && screen->send_mouse_pos != VT200_HIGHLIGHT_MOUSE) {
1113                hi_col = screen->max_col;
1114                while (hi_col > 0 && !(attrs[hi_col] & CHARDRAWN))
1115                    hi_col--;
1116            }
1117
1118            /* remaining piece should be hilited */
1119            hilite = True;
1120        }
1121
1122        if (col > maxcol)
1123            continue;
1124
1125        /*
1126         * Go back to double-sized character dimensions if the line has
1127         * double-width characters.  Note that 'hi_col' is already in the
1128         * right units.
1129         */
1130        if_OPT_DEC_CHRSET({
1131            if (CSET_DOUBLE(*cb)) {
1132                col /= 2;
1133                maxcol /= 2;
1134            }
1135            cs = cb[col];
1136        });
1137
1138        flags = attrs[col];
1139#if OPT_WIDE_CHARS
1140        if (widec)
1141            wideness = iswide(PACK_PAIR(chars, widec, col));
1142        else
1143            wideness = 0;
1144#endif
1145        if_OPT_EXT_COLORS(screen, {
1146            fbf = SCRN_BUF_FGRND(screen, ROW2INX(screen, lastind));
1147            fbb = SCRN_BUF_BGRND(screen, ROW2INX(screen, lastind));
1148            fg_bg = ColorOf(col);
1149            /* this combines them, then splits them again.  but
1150               extract_fg does more, so seems reasonable */
1151            fg = extract_fg(xw, fg_bg, flags);
1152            bg = extract_bg(xw, fg_bg, flags);
1153        });
1154        if_OPT_ISO_TRADITIONAL_COLORS(screen, {
1155            fb = SCRN_BUF_COLOR(screen, ROW2INX(screen, lastind));
1156            fg_bg = ColorOf(col);
1157            fg = extract_fg(xw, fg_bg, flags);
1158            bg = extract_bg(xw, fg_bg, flags);
1159        });
1160
1161        gc = updatedXtermGC(xw, flags, fg_bg, hilite);
1162        gc_changes |= (flags & (FG_COLOR | BG_COLOR));
1163
1164        x = CurCursorX(screen, ROW2INX(screen, row), col);
1165        lastind = col;
1166
1167        for (; col <= maxcol; col++) {
1168            if ((attrs[col] != flags)
1169                || (hilite && (col > hi_col))
1170#if OPT_ISO_COLORS
1171                || ((flags & FG_COLOR)
1172                    && (extract_fg(xw, ColorOf(col), attrs[col]) != fg))
1173                || ((flags & BG_COLOR)
1174                    && (extract_bg(xw, ColorOf(col), attrs[col]) != bg))
1175#endif
1176#if OPT_WIDE_CHARS
1177                || (widec
1178                    && ((iswide(PACK_PAIR(chars, widec, col))) != wideness)
1179                    && !((PACK_PAIR(chars, widec, col)) == HIDDEN_CHAR))
1180#endif
1181#if OPT_DEC_CHRSET
1182                || (cb[col] != cs)
1183#endif
1184                ) {
1185                assert(col >= lastind);
1186                TRACE(("ScrnRefresh looping drawXtermText %d..%d:%s\n",
1187                       lastind, col,
1188                       visibleChars(PAIRED_CHARS(&chars[lastind],
1189                                                 WIDEC_PTR(lastind)),
1190                                    (unsigned) (col - lastind))));
1191
1192                test = flags;
1193                checkVeryBoldColors(test, fg);
1194
1195                x = drawXtermText(xw, test & DRAWX_MASK, gc, x, y,
1196                                  cs,
1197                                  PAIRED_CHARS(&chars[lastind], WIDEC_PTR(lastind)),
1198                                  (unsigned) (col - lastind), 0);
1199
1200                if_OPT_WIDE_CHARS(screen, {
1201                    int i;
1202                    int off;
1203                    for (off = OFF_FINAL; off < MAX_PTRS; off += 2) {
1204                        Char *com_lo = BUFFER_PTR(screen->visbuf,
1205                                                  ROW2INX(screen, row),
1206                                                  off + 0);
1207                        Char *com_hi = BUFFER_PTR(screen->visbuf,
1208                                                  ROW2INX(screen, row),
1209                                                  off + 1);
1210                        for (i = lastind; i < col; i++) {
1211                            int my_x = CurCursorX(screen,
1212                                                  ROW2INX(screen, row),
1213                                                  i);
1214                            int base = PACK_PAIR(chars, widec, i);
1215                            int combo = PACK_PAIR(com_lo, com_hi, i);
1216
1217                            if (iswide(base))
1218                                my_x = CurCursorX(screen,
1219                                                  ROW2INX(screen, row),
1220                                                  i - 1);
1221
1222                            if (combo != 0)
1223                                drawXtermText(xw,
1224                                              (test & DRAWX_MASK)
1225                                              | NOBACKGROUND,
1226                                              gc, my_x, y, cs,
1227                                              PAIRED_CHARS(com_lo + i,
1228                                                           com_hi + i),
1229                                              1, iswide(base));
1230                        }
1231                    }
1232                });
1233
1234                resetXtermGC(xw, flags, hilite);
1235
1236                lastind = col;
1237
1238                if (hilite && (col > hi_col))
1239                    hilite = False;
1240
1241                flags = attrs[col];
1242                if_OPT_EXT_COLORS(screen, {
1243                    fg_bg = ColorOf(col);
1244                    fg = extract_fg(xw, fg_bg, flags);
1245                    bg = extract_bg(xw, fg_bg, flags);
1246                });
1247                if_OPT_ISO_TRADITIONAL_COLORS(screen, {
1248                    fg_bg = ColorOf(col);
1249                    fg = extract_fg(xw, fg_bg, flags);
1250                    bg = extract_bg(xw, fg_bg, flags);
1251                });
1252                if_OPT_DEC_CHRSET({
1253                    cs = cb[col];
1254                });
1255#if OPT_WIDE_CHARS
1256                if (widec)
1257                    wideness = iswide(PACK_PAIR(chars, widec, col));
1258#endif
1259
1260                gc = updatedXtermGC(xw, flags, fg_bg, hilite);
1261                gc_changes |= (flags & (FG_COLOR | BG_COLOR));
1262            }
1263
1264            if (chars[col] == 0) {
1265#if OPT_WIDE_CHARS
1266                if (widec == 0 || widec[col] == 0)
1267#endif
1268                    chars[col] = ' ';
1269            }
1270        }
1271
1272        assert(col >= lastind);
1273        TRACE(("ScrnRefresh calling drawXtermText %d..%d:%s\n",
1274               lastind, col,
1275               visibleChars(PAIRED_CHARS(&chars[lastind], WIDEC_PTR(lastind)),
1276                            (unsigned) (col - lastind))));
1277
1278        test = flags;
1279        checkVeryBoldColors(test, fg);
1280
1281        drawXtermText(xw, test & DRAWX_MASK, gc, x, y,
1282                      cs,
1283                      PAIRED_CHARS(&chars[lastind], WIDEC_PTR(lastind)),
1284                      (unsigned) (col - lastind), 0);
1285
1286        if_OPT_WIDE_CHARS(screen, {
1287            int i;
1288            int off;
1289            for (off = OFF_FINAL; off < MAX_PTRS; off += 2) {
1290                Char *com_lo = BUFFER_PTR(screen->visbuf,
1291                                          ROW2INX(screen, row),
1292                                          off + 0);
1293                Char *com_hi = BUFFER_PTR(screen->visbuf,
1294                                          ROW2INX(screen, row),
1295                                          off + 1);
1296                for (i = lastind; i < col; i++) {
1297                    int my_x = CurCursorX(screen,
1298                                          ROW2INX(screen, row),
1299                                          i);
1300                    int base = PACK_PAIR(chars, widec, i);
1301                    int combo = PACK_PAIR(com_lo, com_hi, i);
1302
1303                    if (iswide(base))
1304                        my_x = CurCursorX(screen,
1305                                          ROW2INX(screen, row),
1306                                          i - 1);
1307
1308                    if (combo != 0)
1309                        drawXtermText(xw,
1310                                      (test & DRAWX_MASK)
1311                                      | NOBACKGROUND,
1312                                      gc, my_x, y, cs,
1313                                      PAIRED_CHARS(com_lo + i,
1314                                                   com_hi + i),
1315                                      1, iswide(base));
1316                }
1317            }
1318        });
1319
1320        resetXtermGC(xw, flags, hilite);
1321    }
1322
1323    /*
1324     * If we're in color mode, reset the various GC's to the current
1325     * screen foreground and background so that other functions (e.g.,
1326     * ClearRight) will get the correct colors.
1327     */
1328    if_OPT_ISO_COLORS(screen, {
1329        if (gc_changes & FG_COLOR)
1330            SGR_Foreground(xw, xw->cur_foreground);
1331        if (gc_changes & BG_COLOR)
1332            SGR_Background(xw, xw->cur_background);
1333    });
1334
1335#if defined(__CYGWIN__) && defined(TIOCSWINSZ)
1336    if (first_time == 1) {
1337        TTYSIZE_STRUCT ts;
1338
1339        first_time = 0;
1340        TTYSIZE_ROWS(ts) = nrows;
1341        TTYSIZE_COLS(ts) = ncols;
1342        ts.ws_xpixel = xw->core.width;
1343        ts.ws_ypixel = xw->core.height;
1344        SET_TTYSIZE(screen->respond, ts);
1345    }
1346#endif
1347    recurse--;
1348}
1349
1350/*
1351 * Call this wrapper to ScrnRefresh() when the data has changed.  If the
1352 * refresh region overlaps the selection, we will release the primary selection.
1353 */
1354void
1355ScrnUpdate(XtermWidget xw,
1356           int toprow,
1357           int leftcol,
1358           int nrows,
1359           int ncols,
1360           Bool force)          /* ... leading/trailing spaces */
1361{
1362    TScreen *screen = &(xw->screen);
1363
1364    if (ScrnHaveSelection(screen)
1365        && (toprow <= screen->endH.row)
1366        && (toprow + nrows - 1 >= screen->startH.row)) {
1367        ScrnDisownSelection(xw);
1368    }
1369    ScrnRefresh(xw, toprow, leftcol, nrows, ncols, force);
1370}
1371
1372/*
1373 * Sets the rows first though last of the buffer of screen to spaces.
1374 * Requires first <= last; first, last are rows of screen->buf.
1375 */
1376void
1377ClearBufRows(XtermWidget xw,
1378             int first,
1379             int last)
1380{
1381    TScreen *screen = &(xw->screen);
1382    unsigned len = MaxCols(screen);
1383    int row;
1384
1385    TRACE(("ClearBufRows %d..%d\n", first, last));
1386    for (row = first; row <= last; row++) {
1387        if_OPT_DEC_CHRSET({
1388            /* clearing the whole row resets the doublesize characters */
1389            SCRN_ROW_CSET(screen, row) = CSET_SWL;
1390        });
1391        ScrnClrWrapped(screen, row);
1392        ClearCells(xw, 0, len, row, 0);
1393    }
1394}
1395
1396/*
1397  Resizes screen:
1398  1. If new window would have fractional characters, sets window size so as to
1399  discard fractional characters and returns -1.
1400  Minimum screen size is 1 X 1.
1401  Note that this causes another ExposeWindow event.
1402  2. Enlarges screen->buf if necessary.  New space is appended to the bottom
1403  and to the right
1404  3. Reduces  screen->buf if necessary.  Old space is removed from the bottom
1405  and from the right
1406  4. Cursor is positioned as closely to its former position as possible
1407  5. Sets screen->max_row and screen->max_col to reflect new size
1408  6. Maintains the inner border (and clears the border on the screen).
1409  7. Clears origin mode and sets scrolling region to be entire screen.
1410  8. Returns 0
1411  */
1412int
1413ScreenResize(XtermWidget xw,
1414             int width,
1415             int height,
1416             unsigned *flags)
1417{
1418    TScreen *screen = &(xw->screen);
1419    int code, rows, cols;
1420    int border = 2 * screen->border;
1421    int move_down_by = 0;
1422#ifdef TTYSIZE_STRUCT
1423    TTYSIZE_STRUCT ts;
1424#endif
1425    Window tw = VWindow(screen);
1426
1427    TRACE(("ScreenResize %dx%d border %d font %dx%d\n",
1428           height, width, border,
1429           FontHeight(screen), FontWidth(screen)));
1430
1431    assert(width > 0);
1432    assert(height > 0);
1433
1434    if (screen->is_running) {
1435        /* clear the right and bottom internal border because of NorthWest
1436           gravity might have left junk on the right and bottom edges */
1437        if (width >= FullWidth(screen)) {
1438            XClearArea(screen->display, tw,
1439                       FullWidth(screen), 0,    /* right edge */
1440                       0, (unsigned) height,    /* from top to bottom */
1441                       False);
1442        }
1443        if (height >= FullHeight(screen)) {
1444            XClearArea(screen->display, tw,
1445                       0, FullHeight(screen),   /* bottom */
1446                       (unsigned) width, 0,     /* all across the bottom */
1447                       False);
1448        }
1449    }
1450
1451    TRACE(("...computing rows/cols: %.2f %.2f\n",
1452           (double) (height - border) / FontHeight(screen),
1453           (double) (width - border - ScrollbarWidth(screen)) / FontWidth(screen)));
1454
1455    rows = (height - border) / FontHeight(screen);
1456    cols = (width - border - ScrollbarWidth(screen)) / FontWidth(screen);
1457    if (rows < 1)
1458        rows = 1;
1459    if (cols < 1)
1460        cols = 1;
1461
1462    /* update buffers if the screen has changed size */
1463    if (MaxRows(screen) != rows || MaxCols(screen) != cols) {
1464        int savelines = (screen->scrollWidget
1465                         ? screen->savelines
1466                         : 0);
1467        int delta_rows = rows - MaxRows(screen);
1468
1469        TRACE(("...ScreenResize chars %dx%d\n", rows, cols));
1470
1471        if (screen->is_running) {
1472            if (screen->cursor_state)
1473                HideCursor();
1474            if (screen->alternate
1475                && xw->misc.resizeGravity == SouthWestGravity)
1476                /* swap buffer pointers back to make this work */
1477                SwitchBufPtrs(screen);
1478            if (screen->altbuf)
1479                (void) Reallocate(xw,
1480                                  &screen->altbuf,
1481                                  &screen->abuf_address,
1482                                  rows,
1483                                  cols,
1484                                  MaxRows(screen),
1485                                  MaxCols(screen));
1486            move_down_by = Reallocate(xw,
1487                                      &screen->allbuf,
1488                                      &screen->sbuf_address,
1489                                      rows + savelines, cols,
1490                                      MaxRows(screen) + savelines,
1491                                      MaxCols(screen));
1492            screen->visbuf = &screen->allbuf[MAX_PTRS * savelines];
1493        }
1494
1495        AdjustSavedCursor(xw, move_down_by);
1496        set_max_row(screen, screen->max_row + delta_rows);
1497        set_max_col(screen, cols - 1);
1498
1499        if (screen->is_running) {
1500            if (xw->misc.resizeGravity == SouthWestGravity) {
1501                screen->savedlines -= move_down_by;
1502                if (screen->savedlines < 0)
1503                    screen->savedlines = 0;
1504                if (screen->savedlines > screen->savelines)
1505                    screen->savedlines = screen->savelines;
1506                if (screen->topline < -screen->savedlines)
1507                    screen->topline = -screen->savedlines;
1508                set_cur_row(screen, screen->cur_row + move_down_by);
1509                screen->cursorp.row += move_down_by;
1510                ScrollSelection(screen, move_down_by, True);
1511
1512                if (screen->alternate)
1513                    SwitchBufPtrs(screen);      /* put the pointers back */
1514            }
1515        }
1516
1517        /* adjust scrolling region */
1518        set_tb_margins(screen, 0, screen->max_row);
1519        *flags &= ~ORIGIN;
1520
1521        if (screen->cur_row > screen->max_row)
1522            set_cur_row(screen, screen->max_row);
1523        if (screen->cur_col > screen->max_col)
1524            set_cur_col(screen, screen->max_col);
1525
1526        screen->fullVwin.height = height - border;
1527        screen->fullVwin.width = width - border - screen->fullVwin.sb_info.width;
1528
1529    } else if (FullHeight(screen) == height && FullWidth(screen) == width)
1530        return (0);             /* nothing has changed at all */
1531
1532    screen->fullVwin.fullheight = height;
1533    screen->fullVwin.fullwidth = width;
1534
1535    ResizeScrollBar(xw);
1536    ResizeSelection(screen, rows, cols);
1537
1538#ifndef NO_ACTIVE_ICON
1539    if (screen->iconVwin.window) {
1540        XWindowChanges changes;
1541        screen->iconVwin.width =
1542            MaxCols(screen) * screen->iconVwin.f_width;
1543
1544        screen->iconVwin.height =
1545            MaxRows(screen) * screen->iconVwin.f_height;
1546
1547        changes.width = screen->iconVwin.fullwidth =
1548            screen->iconVwin.width + 2 * xw->misc.icon_border_width;
1549        changes.height = screen->iconVwin.fullheight =
1550            screen->iconVwin.height + 2 * xw->misc.icon_border_width;
1551        changes.border_width = xw->misc.icon_border_width;
1552
1553        TRACE(("resizing icon window %dx%d\n", changes.height, changes.width));
1554        XConfigureWindow(XtDisplay(xw), screen->iconVwin.window,
1555                         CWWidth | CWHeight | CWBorderWidth, &changes);
1556    }
1557#endif /* NO_ACTIVE_ICON */
1558
1559#ifdef TTYSIZE_STRUCT
1560    /* Set tty's idea of window size */
1561    TTYSIZE_ROWS(ts) = rows;
1562    TTYSIZE_COLS(ts) = cols;
1563#ifdef USE_STRUCT_WINSIZE
1564    ts.ws_xpixel = width;
1565    ts.ws_ypixel = height;
1566#endif
1567    code = SET_TTYSIZE(screen->respond, ts);
1568    TRACE(("return %d from SET_TTYSIZE %dx%d\n", code, rows, cols));
1569    (void) code;
1570
1571#if defined(SIGWINCH) && defined(USE_STRUCT_TTYSIZE)
1572    if (screen->pid > 1) {
1573        int pgrp;
1574
1575        TRACE(("getting process-group\n"));
1576        if (ioctl(screen->respond, TIOCGPGRP, &pgrp) != -1) {
1577            TRACE(("sending SIGWINCH to process group %d\n", pgrp));
1578            kill_process_group(pgrp, SIGWINCH);
1579        }
1580    }
1581#endif /* SIGWINCH */
1582
1583#else
1584    TRACE(("ScreenResize cannot do anything to pty\n"));
1585#endif /* TTYSIZE_STRUCT */
1586    return (0);
1587}
1588
1589/*
1590 * Return true if any character cell starting at [row,col], for len-cells is
1591 * nonnull.
1592 */
1593Bool
1594non_blank_line(TScreen * screen,
1595               int row,
1596               int col,
1597               int len)
1598{
1599    ScrnBuf sb = screen->visbuf;
1600    int i;
1601    Char *ptr = BUF_CHARS(sb, row);
1602
1603    for (i = col; i < len; i++) {
1604        if (ptr[i])
1605            return True;
1606    }
1607
1608    if_OPT_WIDE_CHARS(screen, {
1609        if ((ptr = BUF_WIDEC(sb, row)) != 0) {
1610            for (i = col; i < len; i++) {
1611                if (ptr[i])
1612                    return True;
1613            }
1614        }
1615    });
1616
1617    return False;
1618}
1619
1620/*
1621 * Rectangle parameters start from one.
1622 */
1623#define minRectRow(screen) (getMinRow(screen) + 1)
1624#define minRectCol(screen) (getMinCol(screen) + 1)
1625#define maxRectRow(screen) (getMaxRow(screen) + 1)
1626#define maxRectCol(screen) (getMaxCol(screen) + 1)
1627
1628static int
1629limitedParseRow(XtermWidget xw, TScreen * screen, int row)
1630{
1631    int min_row = minRectRow(screen);
1632    int max_row = maxRectRow(screen);
1633
1634    if (row < min_row)
1635        row = min_row;
1636    else if (row > max_row)
1637        row = max_row;
1638    return row;
1639}
1640
1641static int
1642limitedParseCol(XtermWidget xw, TScreen * screen, int col)
1643{
1644    int min_col = minRectCol(screen);
1645    int max_col = maxRectCol(screen);
1646
1647    (void) xw;
1648    if (col < min_col)
1649        col = min_col;
1650    else if (col > max_col)
1651        col = max_col;
1652    return col;
1653}
1654
1655#define LimitedParse(num, func, dft) \
1656        func(xw, screen, (nparams > num) ? params[num] : dft)
1657
1658/*
1659 * Copy the rectangle boundaries into a struct, providing default values as
1660 * needed.
1661 */
1662void
1663xtermParseRect(XtermWidget xw, int nparams, int *params, XTermRect * target)
1664{
1665    TScreen *screen = &(xw->screen);
1666
1667    memset(target, 0, sizeof(*target));
1668    target->top = LimitedParse(0, limitedParseRow, minRectRow(screen));
1669    target->left = LimitedParse(1, limitedParseCol, minRectCol(screen));
1670    target->bottom = LimitedParse(2, limitedParseRow, maxRectRow(screen));
1671    target->right = LimitedParse(3, limitedParseCol, maxRectCol(screen));
1672    TRACE(("parsed rectangle %d,%d %d,%d\n",
1673           target->top,
1674           target->left,
1675           target->bottom,
1676           target->right));
1677}
1678
1679static Bool
1680validRect(XtermWidget xw, XTermRect * target)
1681{
1682    TScreen *screen = &(xw->screen);
1683
1684    TRACE(("comparing against screensize %dx%d\n",
1685           maxRectRow(screen),
1686           maxRectCol(screen)));
1687    return (target != 0
1688            && target->top >= minRectRow(screen)
1689            && target->left >= minRectCol(screen)
1690            && target->top <= target->bottom
1691            && target->left <= target->right
1692            && target->top <= maxRectRow(screen)
1693            && target->right <= maxRectCol(screen));
1694}
1695
1696/*
1697 * Fills a rectangle with the given 8-bit character and video-attributes.
1698 * Colors and double-size attribute are unmodified.
1699 */
1700void
1701ScrnFillRectangle(XtermWidget xw,
1702                  XTermRect * target,
1703                  int value,
1704                  unsigned flags,
1705                  Bool keepColors)
1706{
1707    TScreen *screen = &(xw->screen);
1708
1709    TRACE(("filling rectangle with '%c' flags %#x\n", value, flags));
1710    if (validRect(xw, target)) {
1711        unsigned left = target->left - 1;
1712        unsigned size = target->right - left;
1713        Char attrs = flags;
1714        int row, col;
1715
1716        attrs &= ATTRIBUTES;
1717        attrs |= CHARDRAWN;
1718        for (row = target->bottom - 1; row >= (target->top - 1); row--) {
1719            TRACE(("filling %d [%d..%d]\n", row, left, left + size));
1720
1721            /*
1722             * Fill attributes, preserving "protected" flag, as well as
1723             * colors if asked.
1724             */
1725            for (col = left; col < target->right; ++col) {
1726                Char temp = SCRN_BUF_ATTRS(screen, row)[col];
1727                if (!keepColors) {
1728                    temp &= ~(FG_COLOR | BG_COLOR);
1729                }
1730                temp = attrs | (temp & (FG_COLOR | BG_COLOR | PROTECTED));
1731                temp |= CHARDRAWN;
1732                SCRN_BUF_ATTRS(screen, row)[col] = temp;
1733#if OPT_ISO_COLORS
1734                if (attrs & (FG_COLOR | BG_COLOR)) {
1735                    if_OPT_EXT_COLORS(screen, {
1736                        SCRN_BUF_FGRND(screen, row)[col] = xw->sgr_foreground;
1737                        SCRN_BUF_BGRND(screen, row)[col] = xw->cur_background;
1738                    });
1739                    if_OPT_ISO_TRADITIONAL_COLORS(screen, {
1740                        SCRN_BUF_COLOR(screen, row)[col] = xtermColorPair(xw);
1741                    });
1742                }
1743#endif
1744            }
1745
1746            memset(SCRN_BUF_CHARS(screen, row) + left, (Char) value, size);
1747            if_OPT_WIDE_CHARS(screen, {
1748                int off;
1749                for (off = OFF_WIDEC; off < MAX_PTRS; ++off) {
1750                    memset(SCREEN_PTR(screen, row, off) + left, 0, size);
1751                }
1752            })
1753        }
1754        ScrnUpdate(xw,
1755                   target->top - 1,
1756                   target->left - 1,
1757                   (target->bottom - target->top) + 1,
1758                   (target->right - target->left) + 1,
1759                   False);
1760    }
1761}
1762
1763#if OPT_DEC_RECTOPS
1764/*
1765 * Copies the source rectangle to the target location, including video
1766 * attributes.
1767 *
1768 * This implementation ignores page numbers.
1769 *
1770 * The reference manual does not indicate if it handles overlapping copy
1771 * properly - so we make a local copy of the source rectangle first, then apply
1772 * the target from that.
1773 */
1774void
1775ScrnCopyRectangle(XtermWidget xw, XTermRect * source, int nparam, int *params)
1776{
1777    TScreen *screen = &(xw->screen);
1778
1779    TRACE(("copying rectangle\n"));
1780
1781    if (validRect(xw, source)) {
1782        XTermRect target;
1783        xtermParseRect(xw,
1784                       ((nparam > 3) ? 2 : (nparam - 1)),
1785                       params,
1786                       &target);
1787        if (validRect(xw, &target)) {
1788            unsigned high = (source->bottom - source->top) + 1;
1789            unsigned wide = (source->right - source->left) + 1;
1790            unsigned size = (high * wide * MAX_PTRS);
1791            int row, col, n, j;
1792
1793            Char *cells = TypeMallocN(Char, size);
1794
1795            if (cells == 0)
1796                return;
1797
1798            TRACE(("OK - make copy %dx%d\n", high, wide));
1799            target.bottom = target.top + (high - 1);
1800            target.right = target.left + (wide - 1);
1801
1802            for (row = source->top - 1; row < source->bottom; ++row) {
1803                for (col = source->left - 1; col < source->right; ++col) {
1804                    n = (((1 + row - source->top) * wide)
1805                         + (1 + col - source->left)) * MAX_PTRS;
1806                    for (j = OFF_ATTRS; j < MAX_PTRS; ++j)
1807                        cells[n + j] = SCREEN_PTR(screen, row, j)[col];
1808                }
1809            }
1810            for (row = target.top - 1; row < target.bottom; ++row) {
1811                for (col = target.left - 1; col < target.right; ++col) {
1812                    if (row >= getMinRow(screen)
1813                        && row <= getMaxRow(screen)
1814                        && col >= getMinCol(screen)
1815                        && col <= getMaxCol(screen)) {
1816                        n = (((1 + row - target.top) * wide)
1817                             + (1 + col - target.left)) * MAX_PTRS;
1818                        for (j = OFF_ATTRS; j < MAX_PTRS; ++j)
1819                            SCREEN_PTR(screen, row, j)[col] = cells[n + j];
1820                        SCRN_BUF_ATTRS(screen, row)[col] |= CHARDRAWN;
1821                    }
1822                }
1823            }
1824            free(cells);
1825
1826            ScrnUpdate(xw,
1827                       (target.top - 1),
1828                       (target.left - 1),
1829                       (target.bottom - target.top) + 1,
1830                       ((target.right - target.left) + 1),
1831                       False);
1832        }
1833    }
1834}
1835
1836/*
1837 * Modifies the video-attributes only - so selection (not a video attribute) is
1838 * unaffected.  Colors and double-size flags are unaffected as well.
1839 *
1840 * FIXME: our representation for "invisible" does not work with this operation,
1841 * since the attribute byte is fully-allocated for other flags.  The logic
1842 * is shown for INVISIBLE because it's harmless, and useful in case the
1843 * CHARDRAWN or PROTECTED flags are reassigned.
1844 */
1845void
1846ScrnMarkRectangle(XtermWidget xw,
1847                  XTermRect * target,
1848                  Bool reverse,
1849                  int nparam,
1850                  int *params)
1851{
1852    TScreen *screen = &(xw->screen);
1853    Bool exact = (screen->cur_decsace == 2);
1854
1855    TRACE(("%s %s\n",
1856           reverse ? "reversing" : "marking",
1857           (exact
1858            ? "rectangle"
1859            : "region")));
1860
1861    if (validRect(xw, target)) {
1862        int top = target->top - 1;
1863        int bottom = target->bottom - 1;
1864        int row, col;
1865        int n;
1866
1867        for (row = top; row <= bottom; ++row) {
1868            int left = ((exact || (row == top))
1869                        ? (target->left - 1)
1870                        : getMinCol(screen));
1871            int right = ((exact || (row == bottom))
1872                         ? (target->right - 1)
1873                         : getMaxCol(screen));
1874
1875            TRACE(("marking %d [%d..%d]\n", row, left, right));
1876            for (col = left; col <= right; ++col) {
1877                unsigned flags = SCRN_BUF_ATTRS(screen, row)[col];
1878
1879                for (n = 0; n < nparam; ++n) {
1880#if OPT_TRACE
1881                    if (row == top && col == left)
1882                        TRACE(("attr param[%d] %d\n", n + 1, params[n]));
1883#endif
1884                    if (reverse) {
1885                        switch (params[n]) {
1886                        case 1:
1887                            flags ^= BOLD;
1888                            break;
1889                        case 4:
1890                            flags ^= UNDERLINE;
1891                            break;
1892                        case 5:
1893                            flags ^= BLINK;
1894                            break;
1895                        case 7:
1896                            flags ^= INVERSE;
1897                            break;
1898                        case 8:
1899                            flags ^= INVISIBLE;
1900                            break;
1901                        }
1902                    } else {
1903                        switch (params[n]) {
1904                        case 0:
1905                            flags &= ~SGR_MASK;
1906                            break;
1907                        case 1:
1908                            flags |= BOLD;
1909                            break;
1910                        case 4:
1911                            flags |= UNDERLINE;
1912                            break;
1913                        case 5:
1914                            flags |= BLINK;
1915                            break;
1916                        case 7:
1917                            flags |= INVERSE;
1918                            break;
1919                        case 8:
1920                            flags |= INVISIBLE;
1921                            break;
1922                        case 22:
1923                            flags &= ~BOLD;
1924                            break;
1925                        case 24:
1926                            flags &= ~UNDERLINE;
1927                            break;
1928                        case 25:
1929                            flags &= ~BLINK;
1930                            break;
1931                        case 27:
1932                            flags &= ~INVERSE;
1933                            break;
1934                        case 28:
1935                            flags &= ~INVISIBLE;
1936                            break;
1937                        }
1938                    }
1939                }
1940#if OPT_TRACE
1941                if (row == top && col == left)
1942                    TRACE(("first mask-change is %#x\n",
1943                           SCRN_BUF_ATTRS(screen, row)[col] ^ flags));
1944#endif
1945                SCRN_BUF_ATTRS(screen, row)[col] = flags;
1946            }
1947        }
1948        ScrnRefresh(xw,
1949                    (target->top - 1),
1950                    (exact ? (target->left - 1) : getMinCol(screen)),
1951                    (target->bottom - target->top) + 1,
1952                    (exact
1953                     ? ((target->right - target->left) + 1)
1954                     : (getMaxCol(screen) - getMinCol(screen) + 1)),
1955                    False);
1956    }
1957}
1958
1959/*
1960 * Resets characters to space, except where prohibited by DECSCA.  Video
1961 * attributes (including color) are untouched.
1962 */
1963void
1964ScrnWipeRectangle(XtermWidget xw,
1965                  XTermRect * target)
1966{
1967    TScreen *screen = &(xw->screen);
1968
1969    TRACE(("wiping rectangle\n"));
1970
1971    if (validRect(xw, target)) {
1972        int top = target->top - 1;
1973        int bottom = target->bottom - 1;
1974        int row, col;
1975
1976        for (row = top; row <= bottom; ++row) {
1977            int left = (target->left - 1);
1978            int right = (target->right - 1);
1979
1980            TRACE(("wiping %d [%d..%d]\n", row, left, right));
1981            for (col = left; col <= right; ++col) {
1982                if (!((screen->protected_mode == DEC_PROTECT)
1983                      && (SCRN_BUF_ATTRS(screen, row)[col] & PROTECTED))) {
1984                    SCRN_BUF_ATTRS(screen, row)[col] |= CHARDRAWN;
1985                    SCRN_BUF_CHARS(screen, row)[col] = ' ';
1986                    if_OPT_WIDE_CHARS(screen, {
1987                        int off;
1988                        for (off = OFF_WIDEC; off < MAX_PTRS; ++off) {
1989                            memset(SCREEN_PTR(screen, row, off) + col, 0, 1);
1990                        }
1991                    })
1992                }
1993            }
1994        }
1995        ScrnUpdate(xw,
1996                   (target->top - 1),
1997                   (target->left - 1),
1998                   (target->bottom - target->top) + 1,
1999                   ((target->right - target->left) + 1),
2000                   False);
2001    }
2002}
2003#endif /* OPT_DEC_RECTOPS */
Note: See TracBrowser for help on using the browser.