📄 terminal.c
字号:
/* terminal.c * (c) 2002 Mikulas Patocka * This file is a part of the Links program, released under GPL. */#include "links.h"void alloc_term_screen(struct terminal *, int, int);void clear_terminal(struct terminal *);void redraw_terminal_ev(struct terminal *, int);void erase_screen(struct terminal *);void redraw_windows(struct terminal *);void empty_window_handler(struct window *, struct event *, int);struct term_spec *get_term_spec(unsigned char *);void unblock_terminal(struct terminal *);int hard_write(int fd, unsigned char *p, int l){ int w = 1; int t = 0; while (l > 0 && w) { if ((w = write(fd, p, l)) < 0) { if (errno == EINTR) continue; return -1; } t += w; p += w; l -= w; } return t;}int hard_read(int fd, unsigned char *p, int l){ int r = 1; int t = 0; while (l > 0 && r) { if ((r = read(fd, p, l)) < 0) { if (errno == EINTR) continue; return -1; } /*{int ww;for(ww=0;ww<r;ww++)fprintf(stderr," %02x",(int)p[ww]);fflush(stderr);}*/ t += r; p += r; l -= r; } return t;}unsigned char *get_cwd(void){ int bufsize = 128; unsigned char *buf; while (1) { buf = mem_alloc(bufsize); if (getcwd(buf, bufsize)) return buf; mem_free(buf); if (errno == EINTR) continue; if (errno != ERANGE) return NULL; if ((unsigned)bufsize > MAXINT - 128) overalloc(); bufsize += 128; } return NULL;}void set_cwd(unsigned char *path){ if (path) while (chdir(path) && errno == EINTR) ;}struct list_head terminals = {&terminals, &terminals};void alloc_term_screen(struct terminal *term, int x, int y){ unsigned *s, *t; NO_GFX; if (x && (unsigned)x * (unsigned)y / (unsigned)x != (unsigned)y) overalloc(); if ((unsigned)x * (unsigned)y > MAXINT / sizeof(unsigned)) overalloc(); s = mem_realloc(term->screen, x * y * sizeof(unsigned)); t = mem_realloc(term->last_screen, x * y * sizeof(unsigned)); memset(t, -1, x * y * sizeof(unsigned)); term->x = x; term->y = y; term->last_screen = t; memset(s, 0, x * y * sizeof(unsigned)); term->screen = s; term->dirty = 1;}void in_term(struct terminal *);void destroy_terminal(struct terminal *);void check_if_no_terminal(void);void clear_terminal(struct terminal *term){ NO_GFX; fill_area(term, 0, 0, term->x, term->y, ' '); set_cursor(term, 0, 0, 0, 0);}void redraw_below_window(struct window *win){ int tr; struct terminal *term = win->term; struct window *end = win; struct event ev = {EV_REDRAW, 0, 0, 0}; NO_GFX; ev.x = term->x; ev.y = term->y; if (term->redrawing >= 2) return; tr = term->redrawing; win->term->redrawing = 2; for (win = term->windows.prev; win != end; win = win->prev) { win->handler(win, &ev, 0); } term->redrawing = tr;}void redraw_terminal_ev(struct terminal *term, int e){ struct window *win; struct event ev = {0, 0, 0, 0}; NO_GFX; ev.ev = e; ev.x = term->x; ev.y = term->y; clear_terminal(term); term->redrawing = 2; foreachback(win, term->windows) win->handler(win, &ev, 0); term->redrawing = 0;}void redraw_terminal(struct terminal *term){ NO_GFX; redraw_terminal_ev(term, EV_REDRAW);}void redraw_terminal_all(struct terminal *term){ NO_GFX; redraw_terminal_ev(term, EV_RESIZE);}void erase_screen(struct terminal *term){ NO_GFX; if (!term->master || !is_blocked()) { if (term->master) want_draw(); hard_write(term->fdout, "\033[2J\033[1;1H", 10); if (term->master) done_draw(); }}void redraw_terminal_cls(struct terminal *term){ NO_GFX; erase_screen(term); alloc_term_screen(term, term->x, term->y); redraw_terminal_all(term);}void cls_redraw_all_terminals(void){ struct terminal *term; foreach(term, terminals) { if (!F) redraw_terminal_cls(term);#ifdef G else { t_resize(term->dev); }#endif }}#ifdef Gint do_rects_intersect(struct rect *r1, struct rect *r2){ return (r1->x1 > r2->x1 ? r1->x1 : r2->x1) < (r1->x2 > r2->x2 ? r2->x2 : r1->x2) && (r1->y1 > r2->y1 ? r1->y1 : r2->y1) < (r1->y2 > r2->y2 ? r2->y2 : r1->y2);}void intersect_rect(struct rect *v, struct rect *r1, struct rect *r2){ v->x1 = r1->x1 > r2->x1 ? r1->x1 : r2->x1; v->x2 = r1->x2 > r2->x2 ? r2->x2 : r1->x2; v->y1 = r1->y1 > r2->y1 ? r1->y1 : r2->y1; v->y2 = r1->y2 > r2->y2 ? r2->y2 : r1->y2;}void unite_rect(struct rect *v, struct rect *r1, struct rect *r2){ if (!is_rect_valid(r1)) { if (v != r2) memcpy(v, r2, sizeof(struct rect)); return; } if (!is_rect_valid(r2)) { if (v != r1) memcpy(v, r1, sizeof(struct rect)); return; } v->x1 = r1->x1 < r2->x1 ? r1->x1 : r2->x1; v->x2 = r1->x2 < r2->x2 ? r2->x2 : r1->x2; v->y1 = r1->y1 < r2->y1 ? r1->y1 : r2->y1; v->y2 = r1->y2 < r2->y2 ? r2->y2 : r1->y2;}int is_rect_valid(struct rect *r1){ return r1->x1 < r1->x2 && r1->y1 < r1->y2;}#define R_GR 8struct rect_set *init_rect_set(void){ struct rect_set *s; s = mem_calloc(sizeof(struct rect_set) + sizeof(struct rect) * R_GR); s->rl = R_GR; s->m = 0; return s;}void add_to_rect_set(struct rect_set **s, struct rect *r){ struct rect_set *ss = *s; int i; if (!is_rect_valid(r)) return; for (i = 0; i < ss->rl; i++) if (!ss->r[i].x1 && !ss->r[i].x2 && !ss->r[i].y1 && !ss->r[i].y2) { x: memcpy(&ss->r[i], r, sizeof(struct rect)); if (i >= ss->m) ss->m = i + 1; return; } if ((unsigned)ss->rl > (MAXINT - sizeof(struct rect_set)) / sizeof(struct rect) - R_GR) overalloc(); ss = mem_realloc(ss, sizeof(struct rect_set) + sizeof(struct rect) * (ss->rl + R_GR)); memset(&(*s = ss)->r[i = (ss->rl += R_GR) - R_GR], 0, sizeof(struct rect) * R_GR); goto x;}void exclude_rect_from_set(struct rect_set **s, struct rect *r){ int i, a; struct rect *rr; do { a = 0; for (i = 0; i < (*s)->m; i++) if (do_rects_intersect(rr = &(*s)->r[i], r)) { struct rect r1, r2, r3, r4; r1.x1 = rr->x1; r1.x2 = rr->x2; r1.y1 = rr->y1; r1.y2 = r->y1; r2.x1 = rr->x1; r2.x2 = r->x1; r2.y1 = r->y1; r2.y2 = r->y2; r3.x1 = r->x2; r3.x2 = rr->x2; r3.y1 = r->y1; r3.y2 = r->y2; r4.x1 = rr->x1; r4.x2 = rr->x2; r4.y1 = r->y2; r4.y2 = rr->y2; intersect_rect(&r2, &r2, rr); intersect_rect(&r3, &r3, rr); rr->x1 = rr->x2 = rr->y1 = rr->y2 = 0;#ifdef DEBUG if (is_rect_valid(&r1) && do_rects_intersect(&r1, r)) internal("bad intersection 1"); if (is_rect_valid(&r2) && do_rects_intersect(&r2, r)) internal("bad intersection 2"); if (is_rect_valid(&r3) && do_rects_intersect(&r3, r)) internal("bad intersection 3"); if (is_rect_valid(&r4) && do_rects_intersect(&r4, r)) internal("bad intersection 4");#endif add_to_rect_set(s, &r1); add_to_rect_set(s, &r2); add_to_rect_set(s, &r3); add_to_rect_set(s, &r4); a = 1; } } while (a);}/* memory address r must contain one struct rect * x1 is leftmost pixel that is still valid * x2 is leftmost pixel that isn't valid any more * y1, y2 analogically */int restrict_clip_area(struct graphics_device *dev, struct rect *r, int x1, int y1, int x2, int y2){ struct rect v, rr; rr.x1 = x1, rr.x2 = x2, rr.y1 = y1, rr.y2 = y2; if (r) memcpy(r, &dev->clip, sizeof(struct rect)); intersect_rect(&v, &dev->clip, &rr); drv->set_clip_area(dev, &v); return is_rect_valid(&v);}#endifvoid draw_to_window(struct window *win, void (*fn)(struct terminal *term, void *), void *data){ struct terminal *term = win->term; struct window *end = (void *)&term->windows; if (!F) { pr(fn(term, data)) {}; term = win->term; end = (void *)&term->windows; if (win->prev == end || term->redrawing) return; term->redrawing = 1; { struct event ev = {EV_REDRAW, 0, 0, 0}; ev.x = term->x; ev.y = term->y; for (win = win->prev; win != end; win = win->prev) win->handler(win, &ev, 0); } term->redrawing = 0;#ifdef G } else { struct rect r1, *r; struct rect_set *s; int i, a; if (win->prev == end || !(s = init_rect_set())) { pr(fn(term, data)) {}; return; } intersect_rect(&r1, &win->pos, &term->dev->clip); add_to_rect_set(&s, &r1); for (win = win->prev; win != end; win = win->prev) exclude_rect_from_set(&s, &win->pos); a = 0; memcpy(&r1, &term->dev->clip, sizeof(struct rect)); for (i = 0; i < s->m; i++) if (is_rect_valid(r = &s->r[i])) { drv->set_clip_area(term->dev, r); pr(fn(term, data)) return; a = 1; } if (!a) { struct rect empty = { 0, 0, 0, 0 }; drv->set_clip_area(term->dev, &empty); fn(term, data); } drv->set_clip_area(term->dev, &r1); mem_free(s);#endif }}#ifdef Gvoid redraw_windows(struct terminal *term){ struct terminal *t1; struct window *win; foreach(t1, terminals) if (t1 == term) goto ok; return; ok: foreach(win, term->windows) { struct event ev = { EV_REDRAW, 0, 0, 0 }; ev.x = term->x; ev.y = term->y; drv->set_clip_area(term->dev, &win->redr); memset(&win->redr, 0, sizeof(struct rect)); win->handler(win, &ev, 0); } drv->set_clip_area(term->dev, &term->dev->size);}void set_window_pos(struct window *win, int x1, int y1, int x2, int y2){ struct terminal *term = win->term; struct rect r; NO_TXT; r.x1 = x1, r.y1 = y1, r.x2 = x2, r.y2 = y2; if (is_rect_valid(&win->pos) && (x1 > win->pos.x1 || x2 < win->pos.x2 || y1 > win->pos.y1 || y2 < win->pos.y2) && term->redrawing < 2) { struct window *w; for (w = win->next; w != (void *)&win->term->windows; w = w->next) unite_rect(&w->redr, &win->pos, &w->redr); register_bottom_half((void (*)(void *))redraw_windows, term); } memcpy(&win->pos, &r, sizeof(struct rect));}#endifvoid add_window_at_pos(struct terminal *term, void (*handler)(struct window *, struct event *, int), void *data, struct window *at){ struct event ev = {EV_INIT, 0, 0, 0}; struct window *win; ev.x = term->x; ev.y = term->y; win = mem_calloc(sizeof(struct window)); win->handler = handler;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -