#include #include #include "screen.h" #include "edbox.h" #include "indic8.h" #include "streq.h" #include "memclear.h" #define SDLST ((u16 *)0x0230) /* if DOS isn't being used, the config will carve up the $0700-$1fff area for extra scrollback. */ unsigned int *bonus_addrs = (unsigned int *)0xd4; /* aka FR0 */ /* the screen that's currently displaying */ char scr_current; /* the screen that's currently being written to */ char scr_active; static char xpos; void scr_waitvcount_116(void) { while(ANTIC.vcount < 116) /* NOP */; } void scr_init(void) { int i; OS.sdmctl = 0; /* disappear the screen */ scr_waitvcount_116(); *SDLST = DLIST_VIS; OS.chbas = FONT_ADDR_HI; init_pools(); for(i = 0; i < MAX_SCREENS; i++) { screens[i].status = SCR_UNUSED; } scr_create("[server]"); scr_create("[private]"); OS.sdmctl = 0x22; /* show the screen again */ scr_display(0); } char scr_create(const char *name) { char pool, i; /* don't create a duplicate screen */ if( (i = scr_getbyname(name)) ) return i; pool = get_smallest_pool(); for(i = 0; i < MAX_SCREENS; i++) { if(screens[i].status == SCR_UNUSED) { pools[pool].screen_count++; strcpy(screens[i].title, name); screens[i].status = SCR_INACTIVE; screens[i].pool = pool; screens[i].line_list = (line_t *)END_MARKER; screens[i].line_count = screens[i].scrollback_pos = 0; scr_display(i); return i; } } return 0xff; } void scr_destroy(char s) { /* <2 because screens 0 and 1 (server and private) cannot be destroyed */ if(s < 2 || s >= MAX_SCREENS) return; /* don't destroy if already destroyed (or never created) */ if(screens[s].status == SCR_UNUSED) return; pool_reclaim_lines(s); pools[screens[s].pool].screen_count--; screens[s].title[0] = 0; screens[s].status = SCR_UNUSED; screens[s].pool = POOL_UNUSED; screens[s].line_count = screens[s].scrollback_pos = 0; } void render_vis_buf(void) { line_t *line; u8 *vis; int cnt; line = screens[scr_current].line_list; /* skip lines before the current scroll position */ for(cnt = 0; cnt < screens[scr_current].scrollback_pos; cnt++) line = line->next; /* point at bottom line of visbuf */ vis = (u8 *)(SCR_VIS_BUF + LINE_LEN * (SCR_VIS_HEIGHT - 1)); for(cnt = 0; cnt < SCR_VIS_HEIGHT; cnt++) { memcpy(vis, line->data, LINE_LEN); line = line->next; vis -= LINE_LEN; } } void scr_display(char s) { if(s >= MAX_SCREENS) return; if(screens[s].status == SCR_UNUSED) return; screens[s].status = SCR_INACTIVE; scr_current = s; scr_waitvcount_116(); render_vis_buf(); scr_show_status(s); } void scr_scrollback(void) { if(screens[scr_current].scrollback_pos <= screens[scr_current].line_count) { screens[scr_current].scrollback_pos += SCR_VIS_HEIGHT; scr_display(scr_current); } } void scr_end_scrollback(void) { screens[scr_current].scrollback_pos = 0; scr_display(scr_current); } void scr_show_status(char s) { int i; char *p, sc; status_box[0] = (s % 10) + 177; /* inverse number */ status_box[1] = ':'; strncpy(status_box + 2, screens[s].title, 32); p = status_box + 43; /* one space past the 2nd indicator */ for(i = 0; i < MAX_SCREENS; i++) { sc = (i % 10) + '1'; switch(screens[i].status) { case SCR_INACTIVE: /* color0 */ break; case SCR_ACTIVE: /* color1 */ sc |= 0x40; break; case SCR_OTHER: /* color2 */ sc |= 0x80; break; case SCR_HILITE: /* color3 */ sc |= 0xc0; break; default: continue; /* don't show anything for unused */ } *p++ = sc; } if(!edbox_visible) { scr_waitvcount_116(); *dlist_status_lms = (u16)status_box; *dlist_last_line = 0x06; /* ANTIC GR.1 */ } } void scr_refresh(void) { scr_display(scr_current); } char scr_getbyname(const char *name) { char i; if(!name) return 0; for(i = 2; i < MAX_SCREENS; i++) { if(streq_i(name, screens[i].title)) return i; } return 0; } void scr_putc_active(char c) { scr_putc(scr_active, c); } void scr_eol_active(void) { scr_putc(scr_active, '\n'); } void scr_eol_current(void) { scr_putc(scr_current, '\n'); } /* TODO: skip color codes (start with 0x03 or 0x04). if we're going to ever support utf-8, decode it here... also, 0x16 is supposed to be reverse video. not widely used/supported. eventually, this will be rewritten in asm anyway. */ /* FIXME: There is a hidden assumption here: that a sequence of scr_putc(), up to the \n that ends it, will all be sent to the same screen. This is because there's only one xpos variable... */ void scr_putc(char s, char c) { u8 *dest; static char bold = 0; if(s == SCR_CURR) s = scr_current; if(c == '\n') { bold = 0; if(!xpos) return; xpos = LINE_LEN; if(s == scr_current) render_vis_buf(); return; } if(xpos == 0 || xpos == LINE_LEN) { add_line(s); xpos = 0; } dest = screens[s].line_list->data + xpos; if(c & 0x80) { /* utf-8 (or maybe latin-1), we don't support it yet */ c = 0xbf; /* inverse ? */ } else if(c == 0x02) { bold = !bold; return; } else if(c == 0x1d) { /* italics */ c = '/'; } else if(c == 0x1e) { /* strikethru */ c = '-'; } else if(c == 0x1f) { /* underline */ c = '_'; } else if(c == 0x0f) { /* all formatting off */ bold = 0; return; } else if(c < 0x20) { /* unsupported control character */ c += 192; } if(bold) c |= 0x80; *dest = c; xpos++; } void scr_print(char s, const char *text) { while(*text) { scr_putc(s, *text); if(*text == '\n') break; text++; } scr_activate(s); } void scr_print_current(const char *text) { scr_print(scr_current, text); } void scr_print_active(const char *text) { scr_print(scr_active, text); } /* void scr_print_server(const char *text) { scr_print(SCR_SERVER, text); } void scr_print_priv(const char *text) { scr_print(SCR_SERVER, text); } */ void scr_activate(char s) { /* if(s != scr_current) { if(scr_status[s] != SCR_HILITE) scr_status[s] = SCR_ACTIVE; scr_show_status(scr_current); } */ scr_active = s; } char *scr_get_cur_name(void) { char *r = screens[scr_current].title; if(*r) return r; else return 0; }