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

📄 terminal.c

📁 putty
💻 C
📖 第 1 页 / 共 5 页
字号:
    if (bytes_used)
	*bytes_used = b->len;

    return ldata;
}

/*
 * Resize a line to make it `cols' columns wide.
 */
static void resizeline(Terminal *term, termline *line, int cols)
{
    int i, oldcols;

    if (line->cols != cols) {

	oldcols = line->cols;

	/*
	 * This line is the wrong length, which probably means it
	 * hasn't been accessed since a resize. Resize it now.
	 * 
	 * First, go through all the characters that will be thrown
	 * out in the resize (if we're shrinking the line) and
	 * return their cc lists to the cc free list.
	 */
	for (i = cols; i < oldcols; i++)
	    clear_cc(line, i);

	/*
	 * If we're shrinking the line, we now bodily move the
	 * entire cc section from where it started to where it now
	 * needs to be. (We have to do this before the resize, so
	 * that the data we're copying is still there. However, if
	 * we're expanding, we have to wait until _after_ the
	 * resize so that the space we're copying into is there.)
	 */
	if (cols < oldcols)
	    memmove(line->chars + cols, line->chars + oldcols,
		    (line->size - line->cols) * TSIZE);

	/*
	 * Now do the actual resize, leaving the _same_ amount of
	 * cc space as there was to begin with.
	 */
	line->size += cols - oldcols;
	line->chars = sresize(line->chars, line->size, TTYPE);
	line->cols = cols;

	/*
	 * If we're expanding the line, _now_ we move the cc
	 * section.
	 */
	if (cols > oldcols)
	    memmove(line->chars + cols, line->chars + oldcols,
		    (line->size - line->cols) * TSIZE);

	/*
	 * Go through what's left of the original line, and adjust
	 * the first cc_next pointer in each list. (All the
	 * subsequent ones are still valid because they are
	 * relative offsets within the cc block.) Also do the same
	 * to the head of the cc_free list.
	 */
	for (i = 0; i < oldcols && i < cols; i++)
	    if (line->chars[i].cc_next)
		line->chars[i].cc_next += cols - oldcols;
	if (line->cc_free)
	    line->cc_free += cols - oldcols;

	/*
	 * And finally fill in the new space with erase chars. (We
	 * don't have to worry about cc lists here, because we
	 * _know_ the erase char doesn't have one.)
	 */
	for (i = oldcols; i < cols; i++)
	    line->chars[i] = term->basic_erase_char;

#ifdef TERM_CC_DIAGS
	cc_check(line);
#endif
    }
}

/*
 * Get the number of lines in the scrollback.
 */
static int sblines(Terminal *term)
{
    int sblines = count234(term->scrollback);
    if (term->cfg.erase_to_scrollback &&
	term->alt_which && term->alt_screen) {
	    sblines += term->alt_sblines;
    }
    return sblines;
}

/*
 * Retrieve a line of the screen or of the scrollback, according to
 * whether the y coordinate is non-negative or negative
 * (respectively).
 */
static termline *lineptr(Terminal *term, int y, int lineno, int screen)
{
    termline *line;
    tree234 *whichtree;
    int treeindex;

    if (y >= 0) {
	whichtree = term->screen;
	treeindex = y;
    } else {
	int altlines = 0;

	assert(!screen);

	if (term->cfg.erase_to_scrollback &&
	    term->alt_which && term->alt_screen) {
	    altlines = term->alt_sblines;
	}
	if (y < -altlines) {
	    whichtree = term->scrollback;
	    treeindex = y + altlines + count234(term->scrollback);
	} else {
	    whichtree = term->alt_screen;
	    treeindex = y + term->alt_sblines;
	    /* treeindex = y + count234(term->alt_screen); */
	}
    }
    if (whichtree == term->scrollback) {
	unsigned char *cline = index234(whichtree, treeindex);
	line = decompressline(cline, NULL);
    } else {
	line = index234(whichtree, treeindex);
    }

    /* We assume that we don't screw up and retrieve something out of range. */
    if (line == NULL) {
	fatalbox("line==NULL in terminal.c\n"
		 "lineno=%d y=%d w=%d h=%d\n"
		 "count(scrollback=%p)=%d\n"
		 "count(screen=%p)=%d\n"
		 "count(alt=%p)=%d alt_sblines=%d\n"
		 "whichtree=%p treeindex=%d\n\n"
		 "Please contact <putty@projects.tartarus.org> "
		 "and pass on the above information.",
		 lineno, y, term->cols, term->rows,
		 term->scrollback, count234(term->scrollback),
		 term->screen, count234(term->screen),
		 term->alt_screen, count234(term->alt_screen), term->alt_sblines,
		 whichtree, treeindex);
    }
    assert(line != NULL);

    resizeline(term, line, term->cols);
    /* FIXME: should we sort the compressed scrollback out here? */

    return line;
}

#define lineptr(x) (lineptr)(term,x,__LINE__,FALSE)
#define scrlineptr(x) (lineptr)(term,x,__LINE__,TRUE)

static void term_schedule_tblink(Terminal *term);
static void term_schedule_cblink(Terminal *term);

static void term_timer(void *ctx, long now)
{
    Terminal *term = (Terminal *)ctx;
    int update = FALSE;

    if (term->tblink_pending && now - term->next_tblink >= 0) {
	term->tblinker = !term->tblinker;
	term->tblink_pending = FALSE;
	term_schedule_tblink(term);
	update = TRUE;
    }

    if (term->cblink_pending && now - term->next_cblink >= 0) {
	term->cblinker = !term->cblinker;
	term->cblink_pending = FALSE;
	term_schedule_cblink(term);
	update = TRUE;
    }

    if (term->in_vbell && now - term->vbell_end >= 0) {
	term->in_vbell = FALSE;
	update = TRUE;
    }

    if (update ||
	(term->window_update_pending && now - term->next_update >= 0))
	term_update(term);
}

static void term_schedule_update(Terminal *term)
{
    if (!term->window_update_pending) {
	term->window_update_pending = TRUE;
	term->next_update = schedule_timer(UPDATE_DELAY, term_timer, term);
    }
}

/*
 * Call this whenever the terminal window state changes, to queue
 * an update.
 */
static void seen_disp_event(Terminal *term)
{
    term->seen_disp_event = TRUE;      /* for scrollback-reset-on-activity */
    term_schedule_update(term);
}

/*
 * Call when the terminal's blinking-text settings change, or when
 * a text blink has just occurred.
 */
static void term_schedule_tblink(Terminal *term)
{
    if (term->blink_is_real) {
	if (!term->tblink_pending)
	    term->next_tblink = schedule_timer(TBLINK_DELAY, term_timer, term);
	term->tblink_pending = TRUE;
    } else {
	term->tblinker = 1;	       /* reset when not in use */
	term->tblink_pending = FALSE;
    }
}

/*
 * Likewise with cursor blinks.
 */
static void term_schedule_cblink(Terminal *term)
{
    if (term->cfg.blink_cur && term->has_focus) {
	if (!term->cblink_pending)
	    term->next_cblink = schedule_timer(CBLINK_DELAY, term_timer, term);
	term->cblink_pending = TRUE;
    } else {
	term->cblinker = 1;	       /* reset when not in use */
	term->cblink_pending = FALSE;
    }
}

/*
 * Call to reset cursor blinking on new output.
 */
static void term_reset_cblink(Terminal *term)
{
    seen_disp_event(term);
    term->cblinker = 1;
    term->cblink_pending = FALSE;
    term_schedule_cblink(term);
}

/*
 * Call to begin a visual bell.
 */
static void term_schedule_vbell(Terminal *term, int already_started,
				long startpoint)
{
    long ticks_already_gone;

    if (already_started)
	ticks_already_gone = GETTICKCOUNT() - startpoint;
    else
	ticks_already_gone = 0;

    if (ticks_already_gone < VBELL_DELAY) {
	term->in_vbell = TRUE;
	term->vbell_end = schedule_timer(VBELL_DELAY - ticks_already_gone,
					 term_timer, term);
    } else {
	term->in_vbell = FALSE;
    }
}

/*
 * Set up power-on settings for the terminal.
 * If 'clear' is false, don't actually clear the primary screen, and
 * position the cursor below the last non-blank line (scrolling if
 * necessary).
 */
static void power_on(Terminal *term, int clear)
{
    term->alt_x = term->alt_y = 0;
    term->savecurs.x = term->savecurs.y = 0;
    term->alt_savecurs.x = term->alt_savecurs.y = 0;
    term->alt_t = term->marg_t = 0;
    if (term->rows != -1)
	term->alt_b = term->marg_b = term->rows - 1;
    else
	term->alt_b = term->marg_b = 0;
    if (term->cols != -1) {
	int i;
	for (i = 0; i < term->cols; i++)
	    term->tabs[i] = (i % 8 == 0 ? TRUE : FALSE);
    }
    term->alt_om = term->dec_om = term->cfg.dec_om;
    term->alt_ins = term->insert = FALSE;
    term->alt_wnext = term->wrapnext =
        term->save_wnext = term->alt_save_wnext = FALSE;
    term->alt_wrap = term->wrap = term->cfg.wrap_mode;
    term->alt_cset = term->cset = term->save_cset = term->alt_save_cset = 0;
    term->alt_utf = term->utf = term->save_utf = term->alt_save_utf = 0;
    term->utf_state = 0;
    term->alt_sco_acs = term->sco_acs =
        term->save_sco_acs = term->alt_save_sco_acs = 0;
    term->cset_attr[0] = term->cset_attr[1] =
        term->save_csattr = term->alt_save_csattr = CSET_ASCII;
    term->rvideo = 0;
    term->in_vbell = FALSE;
    term->cursor_on = 1;
    term->big_cursor = 0;
    term->default_attr = term->save_attr =
	term->alt_save_attr = term->curr_attr = ATTR_DEFAULT;
    term->term_editing = term->term_echoing = FALSE;
    term->app_cursor_keys = term->cfg.app_cursor;
    term->app_keypad_keys = term->cfg.app_keypad;
    term->use_bce = term->cfg.bce;
    term->blink_is_real = term->cfg.blinktext;
    term->erase_char = term->basic_erase_char;
    term->alt_which = 0;
    term_print_finish(term);
    {
	int i;
	for (i = 0; i < 256; i++)
	    term->wordness[i] = term->cfg.wordness[i];
    }
    if (term->screen) {
	swap_screen(term, 1, FALSE, FALSE);
	erase_lots(term, FALSE, TRUE, TRUE);
	swap_screen(term, 0, FALSE, FALSE);
	if (clear)
	    erase_lots(term, FALSE, TRUE, TRUE);
	term->curs.y = find_last_nonempty_line(term, term->screen) + 1;
	if (term->curs.y == term->rows) {
	    term->curs.y--;
	    scroll(term, 0, term->rows - 1, 1, TRUE);
	}
    } else {
	term->curs.y = 0;
    }
    term->curs.x = 0;
    term_schedule_tblink(term);
    term_schedule_cblink(term);
}

/*
 * Force a screen update.
 */
void term_update(Terminal *term)
{
    Context ctx;

    term->window_update_pending = FALSE;

    ctx = get_ctx(term->frontend);
    if (ctx) {
	int need_sbar_update = term->seen_disp_event;
	if (term->seen_disp_event && term->cfg.scroll_on_disp) {
	    term->disptop = 0;	       /* return to main screen */
	    term->seen_disp_event = 0;
	    need_sbar_update = TRUE;
	}

	if (need_sbar_update)
	    update_sbar(term);
	do_paint(term, ctx, TRUE);
	sys_cursor(term->frontend, term->curs.x, term->curs.y - term->disptop);
	free_ctx(ctx);
    }
}

/*
 * Called from front end when a keypress occurs, to trigger
 * anything magical that needs to happen in that situation.
 */
void term_seen_key_event(Terminal *term)
{
    /*
     * On any keypress, clear the bell overload mechanism
     * completely, on the grounds that large numbers of
     * beeps coming from deliberate key action are likely
     * to be intended (e.g. beeps from filename completion
     * blocking repeatedly).
     */
    term->beep_overloaded = FALSE;
    while (term->beephead) {
	struct beeptime *tmp = term->beephead;
	term->beephead = tmp->next;
	sfree(tmp);
    }
    term->beeptail = NULL;
    term->nbeeps = 0;

    /*
     * Reset the scrollback on keypress, if we're doing that.
     */
    if (term->cfg.scroll_on_key) {
	term->disptop = 0;	       /* return to main screen */
	seen_disp_event(term);
    }
}

/*
 * Same as power_on(), but an external function.
 */
void term_pwron(Terminal *term, int clear)
{
    power_on(term, clear);
    if (term->ldisc)		       /* cause ldisc to notice changes */
	ldisc_send(term->ldisc, NULL, 0, 0);
    term->disptop = 0;
    deselect(term);
    term_update(term);
}

static void set_erase_char(Terminal *term)
{
    term->erase_char = term->basic_erase_char;
    if (term->use_bce)
	term->erase_char.attr = (term->curr_attr &
				 (ATTR_FGMASK | ATTR_BGMASK));
}

/*
 * When the user reconfigures us, we need to check the forbidden-
 * alternate-screen config option, disable raw mouse mode if the
 * user has disabled mouse reporting, and abandon a print job if
 * the user has disabled printing.
 */
void term_reconfig(Terminal *term, Config *cfg)
{
    /*
     * Before adopting the new config, check all those terminal
     * settings which control power-on defaults; and if they've
     * changed, we will modify the current state as well as the
     * default one. The full list is: Auto wrap mode, DEC Origin
     * Mode, BCE, blinking text, character classes.
     */
    int reset_wrap, reset_decom, reset_bce, reset_tblink, reset_charclass;
    int i;

    reset_wrap = (term->cfg.wrap_mode != cfg->wrap_mode);
    reset_decom = (term->cfg.dec_om != cfg->dec_om);
    reset_bce = (term->cfg.bce != cfg->bce);
    reset_tblink = (term->cfg.blinktext != cfg->blinktext);
    reset_charclass = 0;
    for (i = 0; i < lenof(term->cfg.wordness); i++)
	if (term->cfg.wordness[i] != cfg->wordness[i])
	    reset_charclass = 1;

⌨️ 快捷键说明

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