📄 screen.c
字号:
}/* Time critical section. */static inline voidadd_char16(struct string *screen, struct screen_driver *driver, struct screen_char *ch, struct screen_state *state){ unsigned char border = (ch->attr & SCREEN_ATTR_FRAME); unsigned char underline = (ch->attr & SCREEN_ATTR_UNDERLINE); unsigned char bold = (ch->attr & SCREEN_ATTR_BOLD); if (border != state->border && driver->frame_seqs) { state->border = border; add_term_string(screen, driver->frame_seqs[!!border]); } if (underline != state->underline && driver->underline) { state->underline = underline; add_term_string(screen, driver->underline[!!underline]); } if (bold != state->bold) { state->bold = bold; if (bold) { add_bytes_to_string(screen, "\033[1m", 4); } else { /* Force repainting of the other attributes. */ state->color[0] = ch->color[0] + 1; } } if (!compare_color(ch->color, state->color)) { copy_color(state->color, ch->color); add_bytes_to_string(screen, "\033[0", 3); if (driver->color_mode == COLOR_MODE_16) { unsigned char code[6] = ";30;40"; unsigned char bgcolor = TERM_COLOR_BACKGROUND(ch->color); code[2] += TERM_COLOR_FOREGROUND(ch->color); if (!driver->transparent || bgcolor != 0) { code[5] += bgcolor; add_bytes_to_string(screen, code, 6); } else { add_bytes_to_string(screen, code, 3); } } else if (ch->attr & SCREEN_ATTR_STANDOUT) { /* Flip the fore- and background colors for highlighing * purposes. */ add_bytes_to_string(screen, ";7", 2); } if (underline && driver->underline) { add_bytes_to_string(screen, ";4", 2); } /* Check if the char should be rendered bold. */ if (bold) { add_bytes_to_string(screen, ";1", 2); } add_bytes_to_string(screen, "m", 1); } add_char_data(screen, driver, ch->data, border);}#ifdef CONFIG_256_COLORSstatic struct string color256_seqs[] = { /* foreground: */ TERM_STRING("\033[0;38;5;%dm"), /* background: */ TERM_STRING("\033[48;5;%dm"),};static inline voidadd_char_color(struct string *screen, struct string *seq, unsigned char color){ unsigned char color_buf[3]; unsigned char *color_pos = color_buf; int seq_pos = 0; int color_len = 1; check_string_magic(seq); for (; seq->source[seq_pos] != '%'; seq_pos++) ; add_bytes_to_string(screen, seq->source, seq_pos); if (color < 10) { color_pos += 2; } else { int color2; ++color_len; if (color < 100) { ++color_pos; } else { ++color_len; if (color < 200) { color_buf[0] = '1'; color -= 100; } else { color_buf[0] = '2'; color -= 200; } } color2 = (color % 10); color /= 10; color_buf[1] = '0' + color; color = color2; } color_buf[2] = '0' + color; add_bytes_to_string(screen, color_pos, color_len); seq_pos += 2; /* Skip "%d" */ add_bytes_to_string(screen, &seq->source[seq_pos], seq->length - seq_pos);}#define add_background_color(str, seq, chr) add_char_color(str, &(seq)[1], (chr)->color[1])#define add_foreground_color(str, seq, chr) add_char_color(str, &(seq)[0], (chr)->color[0])/* Time critical section. */static inline voidadd_char256(struct string *screen, struct screen_driver *driver, struct screen_char *ch, struct screen_state *state){ unsigned char attr_delta = (ch->attr ^ state->attr); if (attr_delta) { if ((attr_delta & SCREEN_ATTR_FRAME) && driver->frame_seqs) { state->border = !!(ch->attr & SCREEN_ATTR_FRAME); add_term_string(screen, driver->frame_seqs[state->border]); } if ((attr_delta & SCREEN_ATTR_UNDERLINE) && driver->underline) { state->underline = !!(ch->attr & SCREEN_ATTR_UNDERLINE); add_term_string(screen, driver->underline[state->underline]); } if (attr_delta & SCREEN_ATTR_BOLD) { if (ch->attr & SCREEN_ATTR_BOLD) { add_bytes_to_string(screen, "\033[1m", 4); } else { /* Force repainting of the other attributes. */ state->color[0] = ch->color[0] + 1; } } state->attr = ch->attr; } if (!compare_color(ch->color, state->color)) { copy_color(state->color, ch->color); add_foreground_color(screen, color256_seqs, ch); if (!driver->transparent || ch->color[1] != 0) { add_background_color(screen, color256_seqs, ch); } if (ch->attr & SCREEN_ATTR_BOLD) add_bytes_to_string(screen, "\033[1m", 4); if (ch->attr & SCREEN_ATTR_UNDERLINE && driver->underline) { state->underline = !!(ch->attr & SCREEN_ATTR_UNDERLINE); add_term_string(screen, driver->underline[state->underline]); } } add_char_data(screen, driver, ch->data, ch->attr & SCREEN_ATTR_FRAME);}#endif#define add_chars(image_, term_, driver_, state_, ADD_CHAR) \{ \ struct terminal_screen *screen = (term_)->screen; \ int y = screen->dirty_from; \ int ypos = y * (term_)->width; \ int prev_y = -1; \ int xmax = (term_)->width - 1; \ int ymax = (term_)->height - 1; \ struct screen_char *current = &screen->last_image[ypos]; \ struct screen_char *pos = &screen->image[ypos]; \ struct screen_char *prev_pos = NULL; /* Warning prevention. */ \ \ int_upper_bound(&screen->dirty_to, ymax); \ \ for (; y <= screen->dirty_to; y++) { \ int is_last_line = (y == ymax); \ int x = 0; \ \ for (; x <= xmax; x++, current++, pos++) { \ /* Workaround for terminals without * "eat_newline_glitch (xn)", e.g., the cons25 family * of terminals and cygwin terminal. * It prevents display distortion, but char at bottom * right of terminal will not be drawn. * A better fix would be to correctly detects * terminal type, and/or add a terminal option for * this purpose. */ \ \ if (is_last_line && x == xmax) \ break; \ \ if (compare_bg_color(pos->color, current->color)) { \ /* No update for exact match. */ \ if (compare_fg_color(pos->color, current->color)\ && pos->data == current->data \ && pos->attr == current->attr) \ continue; \ \ /* Else if the color match and the data is * ``space''. */ \ if (pos->data <= ' ' && current->data <= ' ' \ && pos->attr == current->attr) \ continue; \ } \ \ /* Move the cursor when @prev_pos is more than 10 chars * away. */ \ if (prev_y != y || prev_pos + 10 <= pos) { \ add_cursor_move_to_string(image_, y + 1, x + 1);\ prev_pos = pos; \ prev_y = y; \ } \ \ for (; prev_pos <= pos ; prev_pos++) \ ADD_CHAR(image_, driver_, prev_pos, state_); \ } \ } \}/* Updating of the terminal screen is done by checking what needs to be updated * using the last screen. */voidredraw_screen(struct terminal *term){ struct screen_driver *driver; struct string image; struct screen_state state = { 0xFF, 0xFF, 0xFF, 0, { 0xFF, 0xFF } }; struct terminal_screen *screen = term->screen; if (!screen || screen->dirty_from > screen->dirty_to) return; if (term->master && is_blocked()) return; driver = get_screen_driver(term); if (!driver) return; if (!init_string(&image)) return; switch (driver->color_mode) { case COLOR_MODE_MONO: case COLOR_MODE_16: add_chars(&image, term, driver, &state, add_char16); break;#ifdef CONFIG_256_COLORS case COLOR_MODE_256: add_chars(&image, term, driver, &state, add_char256); break;#endif case COLOR_MODES: case COLOR_MODE_DUMP: default: INTERNAL("Invalid color mode (%d).", driver->color_mode); return; } if (image.length) { if (driver->color_mode) add_bytes_to_string(&image, "\033[37;40m", 8); add_bytes_to_string(&image, "\033[0m", 4); /* If we ended in border state end the frame mode. */ if (state.border && driver->frame_seqs) add_term_string(&image, driver->frame_seqs[0]); } /* Even if nothing was redrawn, we possibly still need to move * cursor. */ if (image.length || screen->cx != screen->lcx || screen->cy != screen->lcy) { screen->lcx = screen->cx; screen->lcy = screen->cy; add_cursor_move_to_string(&image, screen->cy + 1, screen->cx + 1); } if (image.length) { if (term->master) want_draw(); hard_write(term->fdout, image.source, image.length); if (term->master) done_draw(); } done_string(&image); copy_screen_chars(screen->last_image, screen->image, term->width * term->height); screen->dirty_from = term->height; screen->dirty_to = 0;}voiderase_screen(struct terminal *term){ if (term->master) { if (is_blocked()) return; want_draw(); } hard_write(term->fdout, "\033[2J\033[1;1H", 10); if (term->master) done_draw();}voidbeep_terminal(struct terminal *term){#ifdef CONFIG_WIN32 MessageBeep(MB_ICONEXCLAMATION);#else hard_write(term->fdout, "\a", 1);#endif}struct terminal_screen *init_screen(void){ struct terminal_screen *screen; screen = mem_calloc(1, sizeof(*screen)); if (!screen) return NULL; screen->lcx = -1; screen->lcy = -1; return screen;}/* The two images are allocated in one chunk. *//* TODO: It seems allocation failure here is fatal. We should do something! */voidresize_screen(struct terminal *term, int width, int height){ struct terminal_screen *screen; struct screen_char *image; size_t size, bsize; assert(term && term->screen); screen = term->screen; assert(width >= 0); assert(height >= 0); size = width * height; if (size <= 0) return; bsize = size * sizeof(*image); image = mem_realloc(screen->image, bsize * 2); if (!image) return; screen->image = image; screen->last_image = image + size; memset(screen->image, 0, bsize); memset(screen->last_image, 0xFF, bsize); term->width = width; term->height = height; set_screen_dirty(screen, 0, height);}voiddone_screen(struct terminal_screen *screen){ mem_free_if(screen->image); mem_free(screen);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -