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

📄 terminal.c

📁 远程登陆工具软件源码 用于远程登陆unix
💻 C
📖 第 1 页 / 共 5 页
字号:
		    }
		}
		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)
{
    unsigned long *start, *end;
    int distance, size, i;

    start = term->disptext + topline * (term->cols + 1);
    end = term->disptext + (botline + 1) * (term->cols + 1);
    distance = (lines > 0 ? lines : -lines) * (term->cols + 1);
    size = end - start - distance;
    if (lines > 0) {
	memmove(start, start + distance, size * TSIZE);
	if (term->dispcurs >= start + distance &&
	    term->dispcurs <= start + distance + size)
	    term->dispcurs -= distance;
	for (i = 0; i < distance; i++)
	    (start + size)[i] |= ATTR_INVALID;
    } else {
	memmove(start + distance, start, size * TSIZE);
	if (term->dispcurs >= start && term->dispcurs <= start + size)
	    term->dispcurs += distance;
	for (i = 0; i < distance; i++)
	    start[i] |= 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;
    fix_cpos;
    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;
	fix_cpos;
	if (term->use_bce)
	    term->erase_char = (' ' | ATTR_ASCII |
				(term->curr_attr &
				 (ATTR_FGMASK | ATTR_BGMASK)));
    }
}

/*
 * 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)
{
    unsigned long *ldata;

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

    ldata = lineptr(y);
    if (x == term->cols) {
	ldata[x] &= ~LATTR_WRAPPED2;
    } else {
	if ((ldata[x] & (CHAR_MASK | CSET_MASK)) == UCSWIDE) {
	    ldata[x-1] = ldata[x] =
		(ldata[x-1] &~ (CHAR_MASK | CSET_MASK)) | ATTR_ASCII | ' ';
	}
    }
}

/*
 * 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);
	fix_cpos;
    } else {
	unsigned long *ldata = lineptr(start.y);
	while (poslt(start, end)) {
	    if (start.x == term->cols) {
		if (!erase_lattr)
		    ldata[start.x] &= ~(LATTR_WRAPPED | LATTR_WRAPPED2);
		else
		    ldata[start.x] = LATTR_NORM;
	    } else {
		ldata[start.x] = term->erase_char;
	    }
	    if (incpos(start) && start.y < term->rows)
		ldata = lineptr(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). */
    if (erasing_lines_from_top && !(term->alt_which))
	term->tempsblines = 0;
}

/*
 * Insert or delete characters within the current line. n is +ve if
 * insertion is desired, and -ve for deletion.
 */
static void insch(Terminal *term, int n)
{
    int dir = (n < 0 ? -1 : +1);
    int m;
    pos cursplus;
    unsigned long *ldata;

    n = (n < 0 ? -n : n);
    if (n > term->cols - term->curs.x)
	n = term->cols - term->curs.x;
    m = term->cols - term->curs.x - n;
    cursplus.y = term->curs.y;
    cursplus.x = term->curs.x + n;
    check_selection(term, term->curs, cursplus);
    check_boundary(term, term->curs.x, term->curs.y);
    if (dir < 0)
	check_boundary(term, term->curs.x + n, term->curs.y);
    ldata = lineptr(term->curs.y);
    if (dir < 0) {
	memmove(ldata + term->curs.x, ldata + term->curs.x + n, m * TSIZE);
	while (n--)
	    ldata[term->curs.x + m++] = term->erase_char;
    } else {
	memmove(ldata + term->curs.x + n, ldata + term->curs.x, m * TSIZE);
	while (n--)
	    ldata[term->curs.x + n] = term->erase_char;
    }
}

/*
 * Toggle terminal mode `mode' to state `state'. (`query' indicates
 * whether the mode is a DEC private one or a normal one.)
 */
static void toggle_mode(Terminal *term, int mode, int query, int state)
{
    unsigned long ticks;

    if (query)
	switch (mode) {
	  case 1:		       /* DECCKM: application cursor keys */
	    term->app_cursor_keys = state;
	    break;
	  case 2:		       /* DECANM: VT52 mode */
	    term->vt52_mode = !state;
	    if (term->vt52_mode) {
		term->blink_is_real = FALSE;
		term->vt52_bold = FALSE;
	    } else {
		term->blink_is_real = term->cfg.blinktext;
	    }
	    break;
	  case 3:		       /* DECCOLM: 80/132 columns */
	    deselect(term);
	    if (!term->cfg.no_remote_resize)
		request_resize(term->frontend, state ? 132 : 80, term->rows);
	    term->reset_132 = state;
	    term->alt_t = term->marg_t = 0;
	    term->alt_b = term->marg_b = term->rows - 1;
	    move(term, 0, 0, 0);
	    erase_lots(term, FALSE, TRUE, TRUE);
	    break;
	  case 5:		       /* DECSCNM: reverse video */
	    /*
	     * Toggle reverse video. If we receive an OFF within the
	     * visual bell timeout period after an ON, we trigger an
	     * effective visual bell, so that ESC[?5hESC[?5l will
	     * always be an actually _visible_ visual bell.
	     */
	    ticks = GETTICKCOUNT();
	    /* turn off a previous vbell to avoid inconsistencies */
	    if (ticks - term->vbell_startpoint >= VBELL_TIMEOUT)
		term->in_vbell = FALSE;
	    if (term->rvideo && !state &&    /* we're turning it off... */
		(ticks - term->rvbell_startpoint) < VBELL_TIMEOUT) {/*...soon*/
		/* If there's no vbell timeout already, or this one lasts
		 * longer, replace vbell_timeout with ours. */
		if (!term->in_vbell ||
		    (term->rvbell_startpoint - term->vbell_startpoint <
		     VBELL_TIMEOUT))
		    term->vbell_startpoint = term->rvbell_startpoint;
		term->in_vbell = TRUE; /* may clear rvideo but set in_vbell */
	    } else if (!term->rvideo && state) {
		/* This is an ON, so we notice the time and save it. */
		term->rvbell_startpoint = ticks;
	    }
	    term->rvideo = state;
	    term->seen_disp_event = TRUE;
	    if (state)
		term_update(term);
	    break;
	  case 6:		       /* DECOM: DEC origin mode */
	    term->dec_om = state;
	    break;
	  case 7:		       /* DECAWM: auto wrap */
	    term->wrap = state;
	    break;
	  case 8:		       /* DECARM: auto key repeat */
	    term->repeat_off = !state;
	    break;
	  case 10:		       /* DECEDM: set local edit mode */
	    term->term_editing = state;
	    if (term->ldisc)	       /* cause ldisc to notice changes */
		ldisc_send(term->ldisc, NULL, 0, 0);
	    break;
	  case 25:		       /* DECTCEM: enable/disable cursor */
	    compatibility2(OTHER, VT220);
	    term->cursor_on = state;
	    term->seen_disp_event = TRUE;
	    break;
	  case 47:		       /* alternate screen */
	    compatibility(OTHER);
	    deselect(term);
	    swap_screen(term, term->cfg.no_alt_screen ? 0 : state, FALSE, FALSE);
	    term->disptop = 0;
	    break;
	  case 1000:		       /* xterm mouse 1 */
	    term->xterm_mouse = state ? 1 : 0;
	    set_raw_mouse_mode(term->frontend, state);
	    break;
	  case 1002:		       /* xterm mouse 2 */
	    term->xterm_mouse = state ? 2 : 0;
	    set_raw_mouse_mode(term->frontend, state);
	    break;
	  case 1047:                   /* alternate screen */
	    compatibility(OTHER);
	    deselect(term);
	    swap_screen(term, term->cfg.no_alt_screen ? 0 : state, TRUE, TRUE);
	    term->disptop = 0;
	    break;
	  case 1048:                   /* save/restore cursor */
	    if (!term->cfg.no_alt_screen)
                save_cursor(term, state);
	    if (!state) term->seen_disp_event = TRUE;
	    break;
	  case 1049:                   /* cursor & alternate screen */
	    if (state && !term->cfg.no_alt_screen)
		save_cursor(term, state);
	    if (!state) term->seen_disp_event = TRUE;
	    compatibility(OTHER);
	    deselect(term);
	    swap_screen(term, term->cfg.no_alt_screen ? 0 : state, TRUE, FALSE);
	    if (!state && !term->cfg.no_alt_screen)
		save_cursor(term, state);
	    term->disptop = 0;
	    break;
    } else
	switch (mode) {
	  case 4:		       /* IRM: set insert mode */
	    compatibility(VT102);
	    term->insert = state;
	    break;
	  case 12:		       /* SRM: set echo mode */
	    term->term_echoing = !state;
	    if (term->ldisc)	       /* cause ldisc to notice changes */
		ldisc_send(term->ldisc, NULL, 0, 0);
	    break;
	  case 20:		       /* LNM: Return sends ... */
	    term->cr_lf_return = state;
	    break;

⌨️ 快捷键说明

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