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

📄 terminal.c

📁 远程登陆工具软件源码 用于远程登陆unix
💻 C
📖 第 1 页 / 共 5 页
字号:

void term_free(Terminal *term)
{
    unsigned long *line;
    struct beeptime *beep;

    while ((line = delpos234(term->scrollback, 0)) != NULL)
	sfree(line);
    freetree234(term->scrollback);
    while ((line = delpos234(term->screen, 0)) != NULL)
	sfree(line);
    freetree234(term->screen);
    while ((line = delpos234(term->alt_screen, 0)) != NULL)
	sfree(line);
    freetree234(term->alt_screen);
    sfree(term->disptext);
    while (term->beephead) {
	beep = term->beephead;
	term->beephead = beep->next;
	sfree(beep);
    }
    bufchain_clear(&term->inbuf);
    if(term->print_job)
	printer_finish_job(term->print_job);
    bufchain_clear(&term->printer_buf);
    sfree(term->paste_buffer);
    sfree(term);
}

/*
 * Set up the terminal for a given size.
 */
void term_size(Terminal *term, int newrows, int newcols, int newsavelines)
{
    tree234 *newalt;
    unsigned long *newdisp, *line;
    int i, j;
    int sblen;
    int save_alt_which = term->alt_which;

    if (newrows == term->rows && newcols == term->cols &&
	newsavelines == term->savelines)
	return;			       /* nothing to do */

    deselect(term);
    swap_screen(term, 0, FALSE, FALSE);

    term->alt_t = term->marg_t = 0;
    term->alt_b = term->marg_b = newrows - 1;

    if (term->rows == -1) {
	term->scrollback = newtree234(NULL);
	term->screen = newtree234(NULL);
	term->tempsblines = 0;
	term->rows = 0;
    }

    /*
     * Resize the screen and scrollback. We only need to shift
     * lines around within our data structures, because lineptr()
     * will take care of resizing each individual line if
     * necessary. So:
     * 
     *  - If the new screen is longer, we shunt lines in from temporary
     *    scrollback if possible, otherwise we add new blank lines at
     *    the bottom.
     *
     *  - If the new screen is shorter, we remove any blank lines at
     *    the bottom if possible, otherwise shunt lines above the cursor
     *    to scrollback if possible, otherwise delete lines below the
     *    cursor.
     * 
     *  - Then, if the new scrollback length is less than the
     *    amount of scrollback we actually have, we must throw some
     *    away.
     */
    sblen = count234(term->scrollback);
    /* Do this loop to expand the screen if newrows > rows */
    assert(term->rows == count234(term->screen));
    while (term->rows < newrows) {
	if (term->tempsblines > 0) {
	    /* Insert a line from the scrollback at the top of the screen. */
	    assert(sblen >= term->tempsblines);
	    line = delpos234(term->scrollback, --sblen);
	    term->tempsblines -= 1;
	    addpos234(term->screen, line, 0);
	    term->curs.y += 1;
	    term->savecurs.y += 1;
	} else {
	    /* Add a new blank line at the bottom of the screen. */
	    line = snewn(newcols + 2, TTYPE);
	    line[0] = newcols;
	    for (j = 0; j < newcols; j++)
		line[j + 1] = ERASE_CHAR;
            line[newcols + 1] = LATTR_NORM;
	    addpos234(term->screen, line, count234(term->screen));
	}
	term->rows += 1;
    }
    /* Do this loop to shrink the screen if newrows < rows */
    while (term->rows > newrows) {
	if (term->curs.y < term->rows - 1) {
	    /* delete bottom row, unless it contains the cursor */
	    sfree(delpos234(term->screen, term->rows - 1));
	} else {
	    /* push top row to scrollback */
	    line = delpos234(term->screen, 0);
	    addpos234(term->scrollback, line, sblen++);
	    term->tempsblines += 1;
	    term->curs.y -= 1;
	    term->savecurs.y -= 1;
	}
	term->rows -= 1;
    }
    assert(term->rows == newrows);
    assert(count234(term->screen) == newrows);

    /* Delete any excess lines from the scrollback. */
    while (sblen > newsavelines) {
	line = delpos234(term->scrollback, 0);
	sfree(line);
	sblen--;
    }
    if (sblen < term->tempsblines)
	term->tempsblines = sblen;
    assert(count234(term->scrollback) <= newsavelines);
    assert(count234(term->scrollback) >= term->tempsblines);
    term->disptop = 0;

    /* Make a new displayed text buffer. */
    newdisp = snewn(newrows * (newcols + 1), TTYPE);
    for (i = 0; i < newrows * (newcols + 1); i++)
	newdisp[i] = ATTR_INVALID;
    sfree(term->disptext);
    term->disptext = newdisp;
    term->dispcurs = NULL;

    /* Make a new alternate screen. */
    newalt = newtree234(NULL);
    for (i = 0; i < newrows; i++) {
	line = snewn(newcols + 2, TTYPE);
	line[0] = newcols;
	for (j = 0; j < newcols; j++)
	    line[j + 1] = term->erase_char;
        line[newcols + 1] = LATTR_NORM;
	addpos234(newalt, line, i);
    }
    if (term->alt_screen) {
	while (NULL != (line = delpos234(term->alt_screen, 0)))
	    sfree(line);
	freetree234(term->alt_screen);
    }
    term->alt_screen = newalt;
    term->alt_sblines = 0;

    term->tabs = sresize(term->tabs, newcols, unsigned char);
    {
	int i;
	for (i = (term->cols > 0 ? term->cols : 0); i < newcols; i++)
	    term->tabs[i] = (i % 8 == 0 ? TRUE : FALSE);
    }

    /* Check that the cursor positions are still valid. */
    if (term->savecurs.y < 0)
	term->savecurs.y = 0;
    if (term->savecurs.y >= newrows)
	term->savecurs.y = newrows - 1;
    if (term->curs.y < 0)
	term->curs.y = 0;
    if (term->curs.y >= newrows)
	term->curs.y = newrows - 1;
    if (term->curs.x >= newcols)
	term->curs.x = newcols - 1;
    term->alt_x = term->alt_y = 0;
    term->wrapnext = term->alt_wnext = FALSE;

    term->rows = newrows;
    term->cols = newcols;
    term->savelines = newsavelines;
    fix_cpos;

    swap_screen(term, save_alt_which, FALSE, FALSE);

    update_sbar(term);
    term_update(term);
    if (term->resize_fn)
	term->resize_fn(term->resize_ctx, term->cols, term->rows);
}

/*
 * Hand a function and context pointer to the terminal which it can
 * use to notify a back end of resizes.
 */
void term_provide_resize_fn(Terminal *term,
			    void (*resize_fn)(void *, int, int),
			    void *resize_ctx)
{
    term->resize_fn = resize_fn;
    term->resize_ctx = resize_ctx;
    if (term->cols > 0 && term->rows > 0)
	resize_fn(resize_ctx, term->cols, term->rows);
}

/* Find the bottom line on the screen that has any content.
 * If only the top line has content, returns 0.
 * If no lines have content, return -1.
 */ 
static int find_last_nonempty_line(Terminal * term, tree234 * screen)
{
    int i;
    for (i = count234(screen) - 1; i >= 0; i--) {
	unsigned long *line = index234(screen, i);
	int j;
	int cols = line[0];
	for (j = 0; j < cols; j++) {
	    if (line[j + 1] != term->erase_char) break;
	}
	if (j != cols) break;
    }
    return i;
}

/*
 * Swap screens. If `reset' is TRUE and we have been asked to
 * switch to the alternate screen, we must bring most of its
 * configuration from the main screen and erase the contents of the
 * alternate screen completely. (This is even true if we're already
 * on it! Blame xterm.)
 */
static void swap_screen(Terminal *term, int which, int reset, int keep_cur_pos)
{
    int t;
    tree234 *ttr;

    if (!which)
	reset = FALSE;		       /* do no weird resetting if which==0 */

    if (which != term->alt_which) {
	term->alt_which = which;

	ttr = term->alt_screen;
	term->alt_screen = term->screen;
	term->screen = ttr;
	term->alt_sblines = find_last_nonempty_line(term, term->alt_screen) + 1;
	t = term->curs.x;
	if (!reset && !keep_cur_pos)
	    term->curs.x = term->alt_x;
	term->alt_x = t;
	t = term->curs.y;
	if (!reset && !keep_cur_pos)
	    term->curs.y = term->alt_y;
	term->alt_y = t;
	t = term->marg_t;
	if (!reset) term->marg_t = term->alt_t;
	term->alt_t = t;
	t = term->marg_b;
	if (!reset) term->marg_b = term->alt_b;
	term->alt_b = t;
	t = term->dec_om;
	if (!reset) term->dec_om = term->alt_om;
	term->alt_om = t;
	t = term->wrap;
	if (!reset) term->wrap = term->alt_wrap;
	term->alt_wrap = t;
	t = term->wrapnext;
	if (!reset) term->wrapnext = term->alt_wnext;
	term->alt_wnext = t;
	t = term->insert;
	if (!reset) term->insert = term->alt_ins;
	term->alt_ins = t;
	t = term->cset;
	if (!reset) term->cset = term->alt_cset;
	term->alt_cset = t;
	t = term->utf;
	if (!reset) term->utf = term->alt_utf;
	term->alt_utf = t;
	t = term->sco_acs;
	if (!reset) term->sco_acs = term->alt_sco_acs;
	term->alt_sco_acs = t;
    }

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

    /*
     * This might not be possible if we're called during
     * initialisation.
     */
    if (term->screen)
	fix_cpos;
}

/*
 * 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.
 * 
 * NB this function invalidates all pointers into lines of the
 * screen data structures. In particular, you MUST call fix_cpos
 * after calling scroll() and before doing anything else that
 * uses the cpos shortcut pointer.
 */
static void scroll(Terminal *term, int topline, int botline, int lines, int sb)
{
    unsigned long *line, *line2;
    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);
            line = resizeline(line, term->cols);
	    for (i = 0; i < term->cols; i++)
		line[i + 1] = term->erase_char;
	    line[term->cols + 1] = 0;
	    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);
	    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 to
		 * replace it, or allocate a new one if the
		 * scrollback isn't full.
		 */
		if (sblen == term->savelines) {
		    sblen--, line2 = delpos234(term->scrollback, 0);
		} else {
		    line2 = snewn(term->cols + 2, TTYPE);
		    line2[0] = term->cols;
		    term->tempsblines += 1;
		}
		addpos234(term->scrollback, line, sblen);
		line = line2;

		/*
		 * 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--;
	    }
            line = resizeline(line, term->cols);
	    for (i = 0; i < term->cols; i++)
		line[i + 1] = term->erase_char;
	    line[term->cols + 1] = 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;

⌨️ 快捷键说明

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