⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 terminal.c

📁 putty
💻 C
📖 第 1 页 / 共 5 页
字号:

	tp = term->savecurs;
	if (!reset && !keep_cur_pos)
	    term->savecurs = term->alt_savecurs;
	term->alt_savecurs = tp;
        t = term->save_cset;
        if (!reset && !keep_cur_pos)
            term->save_cset = term->alt_save_cset;
        term->alt_save_cset = t;
        t = term->save_csattr;
        if (!reset && !keep_cur_pos)
            term->save_csattr = term->alt_save_csattr;
        term->alt_save_csattr = t;
        t = term->save_attr;
        if (!reset && !keep_cur_pos)
            term->save_attr = term->alt_save_attr;
        term->alt_save_attr = t;
        t = term->save_utf;
        if (!reset && !keep_cur_pos)
            term->save_utf = term->alt_save_utf;
        term->alt_save_utf = t;
        t = term->save_wnext;
        if (!reset && !keep_cur_pos)
            term->save_wnext = term->alt_save_wnext;
        term->alt_save_wnext = t;
        t = term->save_sco_acs;
        if (!reset && !keep_cur_pos)
            term->save_sco_acs = term->alt_save_sco_acs;
        term->alt_save_sco_acs = t;
    }

    if (reset && term->screen) {
	/*
	 * Yes, this _is_ supposed to honour background-colour-erase.
	 */
	erase_lots(term, FALSE, TRUE, TRUE);
    }
}

/*
 * Update the scroll bar.
 */
static void update_sbar(Terminal *term)
{
    int nscroll = sblines(term);
    set_sbar(term->frontend, nscroll + term->rows,
	     nscroll + term->disptop, term->rows);
}

/*
 * Check whether the region bounded by the two pointers intersects
 * the scroll region, and de-select the on-screen selection if so.
 */
static void check_selection(Terminal *term, pos from, pos to)
{
    if (poslt(from, term->selend) && poslt(term->selstart, to))
	deselect(term);
}

/*
 * Scroll the screen. (`lines' is +ve for scrolling forward, -ve
 * for backward.) `sb' is TRUE if the scrolling is permitted to
 * affect the scrollback buffer.
 */
static void scroll(Terminal *term, int topline, int botline, int lines, int sb)
{
    termline *line;
    int i, seltop, olddisptop, shift;

    if (topline != 0 || term->alt_which != 0)
	sb = FALSE;

    olddisptop = term->disptop;
    shift = lines;
    if (lines < 0) {
	while (lines < 0) {
	    line = delpos234(term->screen, botline);
            resizeline(term, line, term->cols);
	    for (i = 0; i < term->cols; i++)
		copy_termchar(line, i, &term->erase_char);
	    line->lattr = LATTR_NORM;
	    addpos234(term->screen, line, topline);

	    if (term->selstart.y >= topline && term->selstart.y <= botline) {
		term->selstart.y++;
		if (term->selstart.y > botline) {
		    term->selstart.y = botline + 1;
		    term->selstart.x = 0;
		}
	    }
	    if (term->selend.y >= topline && term->selend.y <= botline) {
		term->selend.y++;
		if (term->selend.y > botline) {
		    term->selend.y = botline + 1;
		    term->selend.x = 0;
		}
	    }

	    lines++;
	}
    } else {
	while (lines > 0) {
	    line = delpos234(term->screen, topline);
#ifdef TERM_CC_DIAGS
	    cc_check(line);
#endif
	    if (sb && term->savelines > 0) {
		int sblen = count234(term->scrollback);
		/*
		 * We must add this line to the scrollback. We'll
		 * remove a line from the top of the scrollback if
		 * the scrollback is full.
		 */
		if (sblen == term->savelines) {
		    unsigned char *cline;

		    sblen--;
		    cline = delpos234(term->scrollback, 0);
		    sfree(cline);
		} else
		    term->tempsblines += 1;

		addpos234(term->scrollback, compressline(line), sblen);

		/* now `line' itself can be reused as the bottom line */

		/*
		 * If the user is currently looking at part of the
		 * scrollback, and they haven't enabled any options
		 * that are going to reset the scrollback as a
		 * result of this movement, then the chances are
		 * they'd like to keep looking at the same line. So
		 * we move their viewpoint at the same rate as the
		 * scroll, at least until their viewpoint hits the
		 * top end of the scrollback buffer, at which point
		 * we don't have the choice any more.
		 * 
		 * Thanks to Jan Holmen Holsten for the idea and
		 * initial implementation.
		 */
		if (term->disptop > -term->savelines && term->disptop < 0)
		    term->disptop--;
	    }
            resizeline(term, line, term->cols);
	    for (i = 0; i < term->cols; i++)
		copy_termchar(line, i, &term->erase_char);
	    line->lattr = LATTR_NORM;
	    addpos234(term->screen, line, botline);

	    /*
	     * If the selection endpoints move into the scrollback,
	     * we keep them moving until they hit the top. However,
	     * of course, if the line _hasn't_ moved into the
	     * scrollback then we don't do this, and cut them off
	     * at the top of the scroll region.
	     * 
	     * This applies to selstart and selend (for an existing
	     * selection), and also selanchor (for one being
	     * selected as we speak).
	     */
	    seltop = sb ? -term->savelines : topline;

	    if (term->selstate != NO_SELECTION) {
		if (term->selstart.y >= seltop &&
		    term->selstart.y <= botline) {
		    term->selstart.y--;
		    if (term->selstart.y < seltop) {
			term->selstart.y = seltop;
			term->selstart.x = 0;
		    }
		}
		if (term->selend.y >= seltop && term->selend.y <= botline) {
		    term->selend.y--;
		    if (term->selend.y < seltop) {
			term->selend.y = seltop;
			term->selend.x = 0;
		    }
		}
		if (term->selanchor.y >= seltop &&
		    term->selanchor.y <= botline) {
		    term->selanchor.y--;
		    if (term->selanchor.y < seltop) {
			term->selanchor.y = seltop;
			term->selanchor.x = 0;
		    }
		}
	    }

	    lines--;
	}
    }
#ifdef OPTIMISE_SCROLL
    shift += term->disptop - olddisptop;
    if (shift < term->rows && shift > -term->rows && shift != 0)
	scroll_display(term, topline, botline, shift);
#endif /* OPTIMISE_SCROLL */
}

#ifdef OPTIMISE_SCROLL
/*
 * Add a scroll of a region on the screen into the pending scroll list.
 * `lines' is +ve for scrolling forward, -ve for backward.
 *
 * If the scroll is on the same area as the last scroll in the list,
 * merge them.
 */
static void save_scroll(Terminal *term, int topline, int botline, int lines)
{
    struct scrollregion *newscroll;
    if (term->scrolltail &&
	term->scrolltail->topline == topline && 
	term->scrolltail->botline == botline) {
	term->scrolltail->lines += lines;
    } else {
	newscroll = snew(struct scrollregion);
	newscroll->topline = topline;
	newscroll->botline = botline;
	newscroll->lines = lines;
	newscroll->next = NULL;

	if (!term->scrollhead)
	    term->scrollhead = newscroll;
	else
	    term->scrolltail->next = newscroll;
	term->scrolltail = newscroll;
    }
}

/*
 * Scroll the physical display, and our conception of it in disptext.
 */
static void scroll_display(Terminal *term, int topline, int botline, int lines)
{
    int distance, nlines, i, j;

    distance = lines > 0 ? lines : -lines;
    nlines = botline - topline + 1 - distance;
    if (lines > 0) {
	for (i = 0; i < nlines; i++)
	    for (j = 0; j < term->cols; j++)
		copy_termchar(term->disptext[i], j,
			      term->disptext[i+distance]->chars+j);
	if (term->dispcursy >= 0 &&
	    term->dispcursy >= topline + distance &&
	    term->dispcursy < topline + distance + nlines)
	    term->dispcursy -= distance;
	for (i = 0; i < distance; i++)
	    for (j = 0; j < term->cols; j++)
		term->disptext[nlines+i]->chars[j].attr |= ATTR_INVALID;
    } else {
	for (i = nlines; i-- ;)
	    for (j = 0; j < term->cols; j++)
		copy_termchar(term->disptext[i+distance], j,
			      term->disptext[i]->chars+j);
	if (term->dispcursy >= 0 &&
	    term->dispcursy >= topline &&
	    term->dispcursy < topline + nlines)
	    term->dispcursy += distance;
	for (i = 0; i < distance; i++)
	    for (j = 0; j < term->cols; j++)
		term->disptext[i]->chars[j].attr |= ATTR_INVALID;
    }
    save_scroll(term, topline, botline, lines);
}
#endif /* OPTIMISE_SCROLL */

/*
 * Move the cursor to a given position, clipping at boundaries. We
 * may or may not want to clip at the scroll margin: marg_clip is 0
 * not to, 1 to disallow _passing_ the margins, and 2 to disallow
 * even _being_ outside the margins.
 */
static void move(Terminal *term, int x, int y, int marg_clip)
{
    if (x < 0)
	x = 0;
    if (x >= term->cols)
	x = term->cols - 1;
    if (marg_clip) {
	if ((term->curs.y >= term->marg_t || marg_clip == 2) &&
	    y < term->marg_t)
	    y = term->marg_t;
	if ((term->curs.y <= term->marg_b || marg_clip == 2) &&
	    y > term->marg_b)
	    y = term->marg_b;
    }
    if (y < 0)
	y = 0;
    if (y >= term->rows)
	y = term->rows - 1;
    term->curs.x = x;
    term->curs.y = y;
    term->wrapnext = FALSE;
}

/*
 * Save or restore the cursor and SGR mode.
 */
static void save_cursor(Terminal *term, int save)
{
    if (save) {
	term->savecurs = term->curs;
	term->save_attr = term->curr_attr;
	term->save_cset = term->cset;
	term->save_utf = term->utf;
	term->save_wnext = term->wrapnext;
	term->save_csattr = term->cset_attr[term->cset];
	term->save_sco_acs = term->sco_acs;
    } else {
	term->curs = term->savecurs;
	/* Make sure the window hasn't shrunk since the save */
	if (term->curs.x >= term->cols)
	    term->curs.x = term->cols - 1;
	if (term->curs.y >= term->rows)
	    term->curs.y = term->rows - 1;

	term->curr_attr = term->save_attr;
	term->cset = term->save_cset;
	term->utf = term->save_utf;
	term->wrapnext = term->save_wnext;
	/*
	 * wrapnext might reset to False if the x position is no
	 * longer at the rightmost edge.
	 */
	if (term->wrapnext && term->curs.x < term->cols-1)
	    term->wrapnext = FALSE;
	term->cset_attr[term->cset] = term->save_csattr;
	term->sco_acs = term->save_sco_acs;
	set_erase_char(term);
    }
}

/*
 * This function is called before doing _anything_ which affects
 * only part of a line of text. It is used to mark the boundary
 * between two character positions, and it indicates that some sort
 * of effect is going to happen on only one side of that boundary.
 * 
 * The effect of this function is to check whether a CJK
 * double-width character is straddling the boundary, and to remove
 * it and replace it with two spaces if so. (Of course, one or
 * other of those spaces is then likely to be replaced with
 * something else again, as a result of whatever happens next.)
 * 
 * Also, if the boundary is at the right-hand _edge_ of the screen,
 * it implies something deliberate is being done to the rightmost
 * column position; hence we must clear LATTR_WRAPPED2.
 * 
 * The input to the function is the coordinates of the _second_
 * character of the pair.
 */
static void check_boundary(Terminal *term, int x, int y)
{
    termline *ldata;

    /* Validate input coordinates, just in case. */
    if (x == 0 || x > term->cols)
	return;

    ldata = scrlineptr(y);
    if (x == term->cols) {
	ldata->lattr &= ~LATTR_WRAPPED2;
    } else {
	if (ldata->chars[x].chr == UCSWIDE) {
	    clear_cc(ldata, x-1);
	    clear_cc(ldata, x);
	    ldata->chars[x-1].chr = ' ' | CSET_ASCII;
	    ldata->chars[x] = ldata->chars[x-1];
	}
    }
}

/*
 * Erase a large portion of the screen: the whole screen, or the
 * whole line, or parts thereof.
 */
static void erase_lots(Terminal *term,
		       int line_only, int from_begin, int to_end)
{
    pos start, end;
    int erase_lattr;
    int erasing_lines_from_top = 0;

    if (line_only) {
	start.y = term->curs.y;
	start.x = 0;
	end.y = term->curs.y + 1;
	end.x = 0;
	erase_lattr = FALSE;
    } else {
	start.y = 0;
	start.x = 0;
	end.y = term->rows;
	end.x = 0;
	erase_lattr = TRUE;
    }
    if (!from_begin) {
	start = term->curs;
    }
    if (!to_end) {
	end = term->curs;
	incpos(end);
    }
    if (!from_begin || !to_end)
	check_boundary(term, term->curs.x, term->curs.y);
    check_selection(term, start, end);

    /* Clear screen also forces a full window redraw, just in case. */
    if (start.y == 0 && start.x == 0 && end.y == term->rows)
	term_invalidate(term);

    /* Lines scrolled away shouldn't be brought back on if the terminal
     * resizes. */
    if (start.y == 0 && start.x == 0 && end.x == 0 && erase_lattr)
	erasing_lines_from_top = 1;

    if (term->cfg.erase_to_scrollback && erasing_lines_from_top) {
	/* If it's a whole number of lines, starting at the top, and
	 * we're fully erasing them, erase by scrolling and keep the
	 * lines in the scrollback. */
	int scrolllines = end.y;
	if (end.y == term->rows) {
	    /* Shrink until we find a non-empty row.*/
	    scrolllines = find_last_nonempty_line(term, term->screen) + 1;
	}
	if (scrolllines > 0)
	    scroll(term, 0, scrolllines - 1, scrolllines, TRUE);
    } else {
	termline *ldata = scrlineptr(start.y);
	while (poslt(start, end)) {
	    if (start.x == term->cols) {
		if (!erase_lattr)
		    ldata->lattr &= ~(LATTR_WRAPPED | LATTR_WRAPPED2);
		else
		    ldata->lattr = LATTR_NORM;
	    } else {
		copy_termchar(ldata, start.x, &term->erase_char);
	    }
	    if (incpos(start) && start.y < term->rows) {
		ldata = scrlineptr(start.y);
	    }
	}
    }

    /* After an erase of lines from the top of the screen, we shouldn't
     * bring the lines back again if the terminal enlarges (since the user or
     * application has explictly thrown them away)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -