/* subroutines for multi-window terminal emulation */ #ifdef __GNUC__ # include # include # include #else # include # include #endif #include #include #include "mw.h" #include "mwdefs.h" extern int screen_handle; /* variables used by various routines */ extern long dummy; /* dummy return variable */ extern int sdummy; /* short-sized dummy */ extern int scr_x, scr_y; /* size of the screen */ extern int scr_w, scr_h; extern int fast; /* this makes more updates happen in "scrolled" mode with delayed updates */ extern int jerky_updates; extern int mouseflicker; /* for knowing when to turn it on */ extern int audibell; /* What happens on BEL? */ extern int visibell; extern FNT *curfont; /* current font */ extern WIN_MFDB screen_mf; /* screen descriptor */ extern int mouse; /* for mouse on/off */ extern struct wi_str *wlist; extern int ncolors; /* used by ESCb and ESCc */ #if DEBUG extern char dbstr[]; #define DB(x) put_str(x) #define DB1(x,y) sprintf(dbstr,x,y), put_str(dbstr) #define DB2(x,y,z) sprintf(dbstr,x,y,z), put_str(dbstr) #define DB4(s,a,b,c,d) sprintf(dbstr,s,a,b,c,d), put_str(dbstr) #define DB6(s,a,b,c,d,e,f) sprintf(dbstr,s,a,b,c,d,e,f), put_str(dbstr) #else #define DB(x) #define DB1(x,y) #define DB2(x,y,z) #define DB4(s,a,b,c,d) #define DB6(s,a,b,c,d,e,f) #endif /* the program code... */ char *getmem(size) register long size; { char *got; /* this relies on malloc taking size_t, and size_t being long, */ /* or else not compiling with -mshort */ got = (char *) malloc(size); if (got == NULL) { form_alert(1, "[1][Out of memory][ Ok ]"); } else { bzero(got, size); } return got; } /* * w_open opens a window with the supplied name. The new window is * top, ergo wlist. Puts up an alert & returns -1 on errors. */ int w_open(name, xpos, ypos, xsiz, ysiz, sliders, titles, usefont) char *name; int xpos, ypos, xsiz, ysiz; int sliders, titles; /* nonzero to get that thing */ FNT *usefont; /* ptr to font to use */ { register struct wi_str *wp; int wdes; int wtyp; int tmp_w, tmp_h; wtyp = (sliders ? WI_WITHSLD : 0) | (titles ? WI_WITHTITLE : 0); if (ypos < scr_y) ypos = scr_y; if (xpos < scr_x) xpos = scr_x; wind_calc(0, wtyp, 0, 0, usefont->inc_x*xsiz+2*X0, usefont->inc_y*ysiz+2*Y0, &sdummy, &sdummy, &tmp_w, &tmp_h); if (tmp_w>scr_w) tmp_w = scr_w; /* full size <= screen size */ if (tmp_h>scr_h) tmp_h = scr_h; wp = (struct wi_str *)getmem(sizeof(struct wi_str)); if (wp == NULL) { return -1; } wp->wi_mf.wpix = 2*X0 + xsiz*usefont->inc_x; wp->wi_mf.hpix = 2*Y0 + ysiz*usefont->inc_y; wp->wi_mf.wwords = (wp->wi_mf.wpix>>4) +1; wp->wi_mf.planes = 1; wp->font = usefont; wp->fgbg[1] = 0; /* foreground color for vrt_copyfm */ wp->fgbg[0] = 1; /* background color for vrt_copyfm */ /* allocate a screen image for this window before wind_create */ wp->wi_mf.ptr = (short *)getmem( ((long)wp->wi_mf.hpix + wp->font->inc_y*MAXSCROLLED) * wp->wi_mf.wwords*2); if (wp->wi_mf.ptr == NULL) { free(wp); return -1; } wdes = wind_create(wtyp, scr_x, scr_y, tmp_w, tmp_h); if (wdes < 0) { form_alert(1, "[1][Sorry, GEM has|no more windows|for us...][Ok]"); free(wp->wi_mf.ptr); free(wp); return -1; } /* install at head of wlist list (which is sorted by window depth) */ if (wlist == NULL) { wp->next = wp->prev = wp; } else { wp->next = wlist; wp->prev = wlist->prev; wlist->prev->next = wp; wlist->prev = wp; } wlist = wp; wp->sliders = sliders; wp->titles = titles; wp->aes_handle = wdes; wp->wi_w = X0*2 + usefont->inc_x*xsiz; wp->wi_h = Y0*2 + usefont->inc_y*ysiz; wp->wi_style = wtyp; wp->wi_mainstyle = wtyp; w_rename(wp, name); if (!fast) graf_growbox(0, 0, 20, 10, xpos, ypos, tmp_w, tmp_h); wind_open(wdes, xpos, ypos, tmp_w, tmp_h); wind_get(wdes, WF_WORKXYWH, &wp->x, &wp->y, &wp->w, &wp->h); wp->fulled = 0; wp->x_off = 0; wp->y_off = 0; wp->px_off = 0; wp->py_off = 0; wp->m_off = wp->x & 15; /* when is this used? */ wp->cur_x = X0; wp->cur_y = Y0; wp->top_y = Y0; wp->x_chrs = xsiz; wp->y_chrs = ysiz; setvslide(wp); sethslide(wp); return 0; } /* * w_closei removes a window but does not release its storage. This is used * if the window contents must be saved for later use. */ void w_closei(wp) struct wi_str *wp; { int xx, yy, ww, hh; int wdes = wp->aes_handle; wind_get(wdes, WF_CURRXYWH, &xx, &yy, &ww, &hh); wind_close(wdes); if (!fast) graf_shrinkbox(0, 0, 20, 10, xx, yy, ww, hh); wind_delete(wdes); } /* * w_close removes a window. */ void w_close(wp) struct wi_str *wp; { /* unlink me */ wp->prev->next = wp->next; wp->next->prev = wp->prev; if (wp->next == wp) wlist = NULL; /* singleton list */ else if (wlist == wp) wlist = wp->next; w_closei(wp); free(wp->wi_mf.ptr); free(wp); } /* w_resize resizes an existing window. Also lets you pass in the * sliders & titles arguments for the newly-sized window. * * This used to relocate the window; now it copies the xy. * This used to change the font in the window; now it doesn't unless * chfont == 1. */ int w_resize(wp1, xsiz, ysiz, sliders, titles, chfont) struct wi_str *wp1; int xsiz, ysiz; int sliders, titles; int chfont; /* flag: when 0 don't change font */ { struct wi_str *wp2; static int c[8]; int tmp_x, tmp_y, tmp_w, tmp_h, wtyp; int curstate; int retcode; curstate = wp1->curstate; if (curstate) { w_flash(wp1,0); } w_closei(wp1); /* close it (closes AES window) */ /* * what's happening here is that the overlap of screen images between * the old & new sizes gets copied into the new window. This is done by * deleting the old window, creating a new one of the new size, and * copying the appropriate rectangle of screen image over. */ /* unlink me */ wp1->prev->next = wp1->next; wp1->next->prev = wp1->prev; if (wp1->next == wp1) wlist = NULL; else if (wlist == wp1) wlist = wp1->next; wtyp = (sliders ? WI_WITHSLD : 0) | (titles ? WI_WITHTITLE : 0); wind_calc(0,wtyp,wp1->x,wp1->y,wp1->w,wp1->h, &tmp_x, &tmp_y, &tmp_w, &tmp_h); /* open this window with the same workxy as the previous */ if (w_open(wp1->name, tmp_x, tmp_y, xsiz, ysiz, sliders, titles, (chfont ? curfont : wp1->font))) { /* error opening the new copy of the window */ retcode = -1; goto freeold; } wp2 = wlist; c[0] = wp1->m_off; c[1] = wp1->top_y + max(0, wp1->wi_mf.hpix - wp2->wi_mf.hpix); c[2] = c[0] + min(wp1->wi_mf.wpix, wp2->wi_mf.wpix); c[3] = c[1] + min(wp1->wi_mf.hpix, wp2->wi_mf.hpix); c[4] = wp2->m_off; c[5] = wp2->top_y; c[6] = c[4] + min(wp1->wi_mf.wpix, wp2->wi_mf.wpix); c[7] = c[5] + min(wp1->wi_mf.hpix, wp2->wi_mf.hpix); /* copy screen */ vro_cpyfm(screen_handle, FM_COPY, c, &wp1->wi_mf, &wp2->wi_mf); /* copy parameters */ wp2->fgbg[0] = wp1->fgbg[0]; wp2->fgbg[1] = wp1->fgbg[1]; wp2->insmode = wp1->insmode; wp2->fd = wp1->fd; wp2->pid = wp1->pid; if (wtyp != wp1->wi_mainstyle) { /* you're changing the style... copy mainstyle from the original */ wp2->wi_mainstyle = wp1->wi_mainstyle; } /* * if font changed, put cursor at bottom left. Else put it at old X * offset (or right edge if narrower than that), and I can't figure out * the calculation for Y. */ if (wp2->font != wp1->font) { wp2->cur_x = X0; wp2->cur_y = (wp2->y_chrs - 1) * wp2->font->inc_y + Y0; } else { wp2->cur_x = (wp2->x_chrs - 1) * wp2->font->inc_x + X0; if (wp1->cur_x < wp2->cur_x) wp2->cur_x = wp1->cur_x; wp2->cur_y = max(0, wp1->cur_y - c[1]) + Y0; } wp2->state = wp1->state; strcpy(wp2->nuname,wp1->nuname); wp2->nuptr = wp1->nuptr; w_flash(wp2,curstate); retcode = 0; freeold: free(wp1->wi_mf.ptr); free(wp1); return retcode; /* old window is GONE if this is -1 */ } /* w_rename changes the title bar of a window */ void w_rename(wp, name) struct wi_str *wp; char *name; { if (name) strcpy(wp->name, name); if (wp->wi_style & NAME) { wind_set(wp->aes_handle, WF_NAME, wp->name, 0, 0); } } /* w_redraw redraws part of the screen from window contents. * The coordinates are screen relative. */ void w_redraw(wp, logic, xx, yy, ww, hh) struct wi_str *wp; int logic,xx,yy,ww,hh; { int c[8]; GRECT t1, t2; int wdes = wp->aes_handle; /* turn vro_cpyfm logic ops into vrt_cpyfm ones */ if (logic == FM_INVERT) logic = 3; else logic = 1; if (xx+ww > scr_w) ww = scr_w - xx; if (yy+hh > scr_h+scr_y) hh = scr_h+scr_y - yy; t2.g_x = xx; t2.g_y = yy; t2.g_w = ww; t2.g_h = hh; t1.g_x = wp->x; t1.g_y = wp->y; t1.g_w = wp->w; t1.g_h = wp->h; if (!rc_intersect(&t2, &t1)) { return; /* nothing to do... */ } *(long *)0x003ffffc = 1; wind_update(TRUE); *(long *)0x003ffffc = 2; wind_get(wdes, WF_FIRSTXYWH, &t1.g_x, &t1.g_y, &t1.g_w, &t1.g_h); while (t1.g_w && t1.g_h) { if (rc_intersect(&t2, &t1)) { if (mouse) { /* we have to do graphics, so switch the mouse off. * mouse will be switched on again in main loop. * this is ugly, but it improves speed a bit... * (If mouseflicker is ON, we'll turn it on again below) */ mouse = 0; graf_mouse(M_OFF, NULL); } c[0] = t1.g_x - wp->x + wp->x_off + wp->m_off; c[1] = t1.g_y - wp->y + wp->y_off + wp->top_y - Y0; c[2] = c[0] + t1.g_w - 1; c[3] = c[1] + t1.g_h - 1; c[4] = t1.g_x; c[5] = t1.g_y; c[6] = c[4] + t1.g_w - 1; c[7] = c[5] + t1.g_h - 1; vrt_cpyfm(screen_handle, logic, c, &wp->wi_mf, &screen_mf, wp->fgbg); } *(long *)0x003ffffc = 3; wind_get(wdes, WF_NEXTXYWH, &t1.g_x, &t1.g_y, &t1.g_w, &t1.g_h); } *(long *)0x003ffffc = 4; wind_update(FALSE); /* mouse stays hidden -- we'll make it visible next time it moves */ /* except if mouseflicker is on, in which case we'll do it NOW */ if (!mouse && mouseflicker) { mouse = 1; graf_mouse(M_ON,NULL); } } /* w_update copies a portion of the window to the screen. Coordinates * are window-relative */ void w_update(wp, logic, xx, yy, ww, hh) struct wi_str *wp; int logic, xx,yy,ww,hh; { w_redraw(wp, logic, xx + wp->x - wp->x_off, yy + wp->y - wp->y_off - wp->top_y + Y0, ww, hh); } /* w_move sets the window's idea of its own position on the screen */ void w_move(wp, xx, yy, ww, hh) struct wi_str *wp; int xx, yy, ww, hh; { int wdes = wp->aes_handle; int flag = 0; int m_w, m_h; int x1, x2; int tmp; int c[8]; int inc_x, inc_y; wind_calc(1, wp->wi_style, xx, yy, ww, hh, &sdummy, &sdummy, &m_w, &m_h); if (tmp = (m_w-2*X0)%wp->font->inc_x) { ww -= tmp; m_w -= tmp; } if (tmp = (m_h-2*Y0)%wp->font->inc_y) { hh -= tmp; m_h -= tmp; } if (m_w>wp->wi_w) ww = ww-(m_w-wp->wi_w); if (m_h>wp->wi_h) hh = hh-(m_h-wp->wi_h); wind_set(wdes, WF_CURRXYWH, xx, yy, ww, hh); wind_get(wdes, WF_WORKXYWH, &wp->x, &wp->y, &wp->w, &wp->h); if (wp->x_off+wp->w > wp->wi_w) { inc_x = wp->font->inc_x; flag = 1; wp->x_off = (wp->wi_w - wp->w)/inc_x*inc_x; } if (wp->y_off+wp->h > wp->wi_h) { inc_y = wp->font->inc_y; flag = 1; wp->y_off = (wp->wi_h - wp->h)/inc_y*inc_y; } x1 = wp->m_off; x2 = (wp->x - wp->x_off) & 15; if (x1 != x2) { c[0] = x1; c[1] = wp->top_y; /* displayed part of memory form starts here */ c[2] = x1 + wp->wi_w - 1; c[3] = wp->wi_h - 1 + c[1]; c[4] = x2; c[5] = c[1]; c[6] = x2 + wp->wi_w - 1; c[7] = c[3]; vro_cpyfm(screen_handle, FM_COPY, c, &wp->wi_mf, &wp->wi_mf); wp->m_off = x2; } if (flag) w_redraw(wp, FM_COPY, wp->x, wp->y, wp->w, wp->h); setvslide(wp); sethslide(wp); } /* * w_top makes win the top window. */ void w_top(wp) struct wi_str *wp; { wind_set(wp->aes_handle, WF_TOP, 0, 0, 0, 0); if (wlist == wp) return; /* already top of list */ /* unlink from its current place */ wp->next->prev = wp->prev; wp->prev->next = wp->next; /* link into top */ wp->next = wlist; wp->prev = wlist->prev; wlist->prev->next = wp; wlist->prev = wp; wlist = wp; } /* * w_bottom finds the bottom window and puts it on top */ void w_bottom() { struct wi_str *wp; if (!wlist || wlist->next == wlist) return; for (wp = wlist->next; wp->next != wlist; wp = wp->next) /* do nothing */ ; w_top(wp); } /* * w_hide puts the top window on the bottom. * (a.k.a. "bury") */ void w_hide() { struct wi_str *wp, *oldtop; /* top all the windows, in order, from back to front, except the first. */ if (!wlist || wlist->next == wlist) return; /* empty or singleton list */ oldtop = wlist; /* window NOT to top */ for (wp = wlist->prev; wp != oldtop; wp = wp->prev) wind_set(wp->aes_handle,WF_TOP, 0,0,0,0); /* move the top element from wlist to the end of wlist (easy!) */ wlist = wlist->next; } #define TINYX 80 #define TINYY 70 /* * w_shrink saves current size and location and shrinks to standard tiny size. * The second from the top non-shrunk window is placed on top. */ void w_shrink(wp) struct wi_str *wp; { int wdes = wp->aes_handle; int curx, cury, curw, curh; static int slotcount; /* * Don't shrink a window that is currently shrunk */ wind_get(wdes, WF_CURRXYWH, &curx, &cury, &curw, &curh); if (curw <= TINYX && cury <= TINYY) return; if (wp->slotno == 0) wp->slotno = ++slotcount; /* * By setting wp->fulled to one and the "previous" size to tiny, * we're saying that the current size is the "full" size, and we * want to "toggle to" the tiny size. */ wp->fulled = 1; wp->px = scr_x + (scr_w - TINYX + 2); wp->py = scr_y + ((wp->slotno-1) * (TINYY + 2)); wp->pw = TINYX; wp->ph = TINYY; /* ensure at least 10 dots of title bar on screen */ if (wp->py + 10 > scr_y + scr_h) { wp->py = wp->py - scr_h + 10; wp->px = scr_x + scr_w - TINYY * 2; } w_full(wp); /* now top the topmost window which isn't already tiny */ wp = wlist; do { wdes = wp->aes_handle; wind_get(wdes, WF_CURRXYWH, &curx, &cury, &curw, &curh); if (curw > TINYX || curh > TINYY) { w_full(wp); w_top(wp); return; } wp = wp->next; } while (wp != wlist); /* no windows are not shrunk; just leave 'em */ } /* w_full toggles size and location between the current size and * the "previous" size. */ void w_full(wp) struct wi_str *wp; { int x1, y1, w1, h1; int x2, y2, w2, h2; int full; int wdes = wp->aes_handle; full = wp->fulled; /* if already full, set to "previous" size, else to full size */ if (full) { x1 = wp->px; y1 = wp->py; w1 = wp->pw; h1 = wp->ph; } else wind_get(wdes, WF_FULLXYWH, &x1, &y1, &w1, &h1); wind_get(wdes, WF_CURRXYWH, &x2, &y2, &w2, &h2); wp->px = x2; wp->py = y2; wp->pw = w2; wp->ph = h2; if (!fast) { if (w2>=w1) graf_growbox(x1, y1, w1, h1, x2, y2, w2, h2); else graf_shrinkbox(x1, y1, w1, h1, x2, y2, w2, h2); } x2 = wp->x_off; y2 = wp->y_off; wp->x_off = wp->px_off; wp->y_off = wp->py_off; wp->px_off = x2; wp->py_off = y2; w_move(wp, x1, y1, w1, h1); w_redraw(wp, FM_COPY, wp->x, wp->y, wp->w, wp->h); wp->fulled = 1; } void w_arrow(wp, arrow) struct wi_str *wp; int arrow; { int inc_x = wp->font->inc_x; int inc_y = wp->font->inc_y; switch (arrow) { case 0: /* page up */ wp->y_off -= wp->h/inc_y*inc_y; goto y_upd; case 1: /* page down */ wp->y_off += wp->h/inc_y*inc_y; goto y_upd; case 2: /* row up */ wp->y_off -= inc_y; goto y_upd; case 3: /* row down */ wp->y_off += inc_y; goto y_upd; case 4: /* page left */ wp->x_off -= wp->w/inc_x*inc_x; goto x_upd; case 5: /* page right */ wp->x_off += wp->w/inc_x*inc_x; goto x_upd; case 6: /* column left */ wp->x_off -= inc_x; goto x_upd; case 7: /* column right */ wp->x_off += inc_x; goto x_upd; } x_upd: if (wp->x_off<0) wp->x_off = 0; else if (wp->x_off+wp->w > wp->wi_w) wp->x_off = (wp->wi_w - wp->w)/inc_x*inc_x; sethslide(wp); goto upd; y_upd: if (wp->y_off<0) wp->y_off = 0; else if (wp->y_off+wp->h > wp->wi_h) wp->y_off = (wp->wi_h - wp->h)/inc_y*inc_y; setvslide(wp); upd: w_redraw(wp, FM_COPY, wp->x, wp->y, wp->w, wp->h); } void w_slide(wp, hor, val) struct wi_str *wp; int hor, val; { int tmp; if (hor) { tmp = wp->font->inc_x; wp->x_off = ((long)val*(wp->wi_w-wp->w)/1000)/tmp*tmp; sethslide(wp); } else { tmp = wp->font->inc_y; wp->y_off = ((long)val*(wp->wi_h-wp->h)/1000)/tmp*tmp; setvslide(wp); } w_redraw(wp, FM_COPY, wp->x, wp->y, wp->w, wp->h); } void sethslide(wp) struct wi_str *wp; { int tmp; int wdes = wp->aes_handle; if (wp->wi_style & HSLIDE) { if (wp->wi_w == wp->w) tmp = 0; else tmp = (long)1000*wp->x_off/(wp->wi_w-wp->w); if (tmp != wp->hspos) { wind_set(wdes, WF_HSLIDE, tmp, 0, 0, 0); wp->hspos = tmp; } tmp = (long)1000*wp->w/wp->wi_w; if (tmp != wp->hssiz) { wind_set(wdes, WF_HSLSIZE, tmp, 0, 0, 0); wp->hssiz = tmp; } } } void setvslide(wp) struct wi_str *wp; { int tmp; int wdes = wp->aes_handle; if (wp->wi_style & VSLIDE) { if (wp->wi_h == wp->h) tmp = 0; else tmp = (long)1000*wp->y_off/(wp->wi_h-wp->h); if (tmp != wp->vspos) { wind_set(wdes, WF_VSLIDE, tmp, 0, 0, 0); wp->vspos = tmp; } tmp = (long)1000*wp->h/wp->wi_h; if (tmp != wp->vssiz) { wind_set(wdes, WF_VSLSIZE, tmp, 0, 0, 0); wp->vssiz = tmp; } } } /* * flash the cursor in a window; if it's not the last one we flashed, * un_flash that one */ void w_flash(wp, state) struct wi_str *wp; int state; { static struct wi_str *wp_last = NULL; int wdes; int t[8]; wdes = wp->aes_handle; if (wp_last && wp != wp_last) w_flash(wp_last, 1); wp_last = wp; if (wp->curstate == state) return; if (state == 2) wp->curstate = !wp->curstate; else wp->curstate = state; t[0] = t[4] = wp->cur_x + wp->m_off; t[1] = t[5] = wp->cur_y; t[2] = t[6] = t[0]+wp->font->inc_x-1; t[3] = t[7] = t[1]+wp->font->inc_y-1; vro_cpyfm(screen_handle, FM_INVERT, t, &wp->wi_mf, &wp->wi_mf); w_update(wp, FM_COPY, wp->cur_x, wp->cur_y, wp->font->inc_x, wp->font->inc_y); } /* w_output prints a string onto the window. The string may * contain control chars and escape sequences. Its length is given, * so you can even output NULs. */ void w_output(wp, ptr, charcount) struct wi_str *wp; unsigned char *ptr; short charcount; { int w_handle; unsigned char ch; int inc_x, cur_x; int state; int inc_y, cur_y; int t[8]; int f_x, f_y, f_mod; int scrolled; /* Number of scrolling operations delayed */ int xsiz, ysiz;/* Size in chars of terminal emulation for this window*/ register unsigned char *sptr; register unsigned long *dptr; register unsigned long mask; register int shift; register unsigned long val; int count = 0; char * fdata; long width; char * wimfptr; int moffincx; unsigned char * savptr; if (!wp->font) return; state = wp->state; inc_x = wp->font->inc_x; inc_y = wp->font->inc_y; xsiz = wp->x_chrs; ysiz = wp->y_chrs; f_x = cur_x = wp->cur_x; f_y = cur_y = wp->cur_y; /* * This sets "hard update" any time the bottom N lines of the buffer are * being used -- that is, the overflow below the visible screen. This is * seven lines in 8 when you're doing glass-tty scrolling things. This * is wrong & slow. */ scrolled = wp->top_y/inc_y; fdata = wp->font->f_data; width = 2 * wp->wi_mf.wwords; wimfptr = ((char *) (wp-> wi_mf.ptr)) - 2; moffincx = wp->m_off + inc_x - 1; f_mod = 0; savptr = ptr; w_handle = wp->aes_handle; if (wp->curstate) { w_flash(wp, 0); } while (charcount--) { ch = *ptr++; switch (state) { case S_NORMAL: if (ch >= ' ') { if (wp->insmode) { /* open space for character */ t[0] = cur_x + wp->m_off; t[1] = t[5] = cur_y; t[2] = (xsiz - 1) * inc_x + wp->m_off - 1; t[3] = t[7] = cur_y + inc_y - 1; t[4] = t[0] + inc_x; t[6] = t[2] + inc_x; vro_cpyfm(screen_handle, FM_COPY, t, &wp->wi_mf, &wp->wi_mf); } /* paint the character (only if it's in range for this font) */ if (ch < wp->font->nchars) { sptr = (unsigned char *)(fdata+ch*16); dptr = (unsigned long *)(wimfptr + cur_y*width + (((moffincx + cur_x)>>4)<<1)); shift = 15 - ((moffincx + cur_x)&15); /* to get overstrike, set mask to -1 */ mask = (-1L<<(shift+inc_x)|(1<inverse) { for (count = inc_y; count; count--) { val = ((long)(*sptr++))< inc_x * xsiz) { /* autowrap */ if (wp->discard) { cur_x -= inc_x; /* back to last char position */ } else { cur_y += inc_y; if (cur_y >= wp->top_y + inc_y * ysiz) { wp->top_y += inc_y; ++ scrolled; } if (! scrolled) { w_update(wp, FM_COPY, f_x, f_y, cur_x-f_x, inc_y); f_mod = 0; } cur_x = X0; f_x = cur_x; f_y = cur_y; } } } else { /* not printable character */ /* * If you've modified the screen in this incarnation and you aren't * "scrolled", update before any non-printing character. This * appears to call w_update for the line you're on, from the X you * started from to the X you're at now. I think this is * inefficient, but I'm not sure yet. If you're in insert mode, * update the whole line from the starting X to the end of the * line. * * I changed this to set "scrolled" if you get here and f_mod is * TRUE. That means simple updates on one line (no non-printing * chars) don't happen in "scrolled" mode, but anything more * complicated does. This is also conditional on jerky_updates, * which is the visual result. */ if (f_mod && !scrolled) { if (jerky_updates) scrolled = 1; else { if (wp->insmode) w_update(wp, FM_COPY, f_x, f_y, xsiz * inc_x-f_x, inc_y); else w_update(wp, FM_COPY, f_x, f_y, cur_x - f_x, inc_y); f_mod = 0; } } switch (ch) { case '\007': /* Bell */ if (audibell) (void)Bconout(2, '\007'); if (visibell) { w_redraw(wp, FM_INVERT, wp->x, wp->y, wp->w, wp->h); w_redraw(wp, FM_COPY, wp->x, wp->y, wp->w, wp->h); /* Should clear flag to prevent need for next update? */ } break; case '\r': /* Carriage Return */ cur_x = X0; break; case '\b': /* Backspace */ if (cur_x>X0) cur_x -= inc_x; break; case '\n': /* Newline */ cur_y += inc_y; if (cur_y >= inc_y * ysiz + wp->top_y) { wp->top_y += inc_y; ++ scrolled; } break; case '\t': /* Tab */ cur_x = ((cur_x/inc_x/8+1))*inc_x*8+X0; break; case '\033': /* ESC */ state = S_ESC; count = 0; /* count is used for insert or delete line */ break; } f_x = cur_x; f_y = cur_y; } break; case S_ESC: switch (ch) { case 'H': /* Home */ cur_x = X0; cur_y = wp->top_y; state = S_NORMAL; break; case 'A': /* Cursor Up */ case 'I': /* Reverse Index (doesn't reverse scroll yet) */ if (cur_y!=wp->top_y) { cur_y -= inc_y; } state = S_NORMAL; break; case 'B': /* Cursor Down */ if ((cur_y + inc_y) < (wp->top_y + (inc_y * ysiz))) { cur_y += inc_y; } state = S_NORMAL; break; case 'C': /* Cursor Right */ if (cur_x < (xsiz - 1) * inc_x) cur_x += inc_x; state = S_NORMAL; break; case 'D': /* Cursor Left */ if (cur_x > X0) cur_x -= inc_x; state = S_NORMAL; break; case 'b': /* ST52 color change (foreground) */ state = S_FG; break; case 'c': /* ST52 color change (background) */ state = S_BG; break; case 'E': /* Clear Screen */ f_x = cur_x = X0; wp->top_y = f_y = cur_y = Y0; wp->inverse = 0; wp->insmode = 0; lineerase(wp, 0, ysiz - 1 + MAXSCROLLED); ++ scrolled; state = S_NORMAL; break; case 'j': /* AKP: save cursor location */ wp->save_x = cur_x; wp->save_y = cur_y; state = S_NORMAL; break; case 'k': /* AKP: restore saved location */ f_x = cur_x = wp->save_x; f_x = cur_y = wp->save_y; state = S_NORMAL; break; case 'd': /* Clear from beginning of screen */ lineerase(wp, 0,cur_y/inc_y); /* clear top to this line */ ++scrolled; /* fall through */ case 'o': /* Clear from beginning of line */ t[0] = t[4] = wp->m_off; /* init X */ t[1] = t[5] = cur_y; /* init Y */ t[2] = t[6] = cur_x + wp->m_off; /* final X */ t[3] = t[7] = cur_y+inc_y-1; vro_cpyfm(screen_handle, FM_CLEAR, t, &wp->wi_mf, &wp->wi_mf); ++scrolled; state = S_NORMAL; break; case 'l': /* erase entire line, cursor to left */ t[0] = t[4] = wp->m_off; t[1] = t[5] = cur_y; t[2] = t[6] = X0-1 + xsiz*inc_x + wp->m_off; t[3] = t[7] = cur_y+inc_y-1; vro_cpyfm(screen_handle, FM_CLEAR, t, &wp->wi_mf, &wp->wi_mf); ++scrolled; cur_x = X0; state = S_NORMAL; break; case 'e': /* enable cursor */ wp->cursor_hidden = 0; state = S_NORMAL; break; case 'f': /* disable cursor */ wp->cursor_hidden = 1; state = S_NORMAL; break; case 'J': /* Clear to End of Screen */ lineerase(wp, cur_y / inc_y + 1, ysiz - 1 + wp->top_y / inc_y); if (! scrolled) w_update(wp, FM_COPY, X0, cur_y + inc_y, xsiz*inc_x, ysiz*inc_y); /* fall through */ case 'K': /* Clear to End of Line */ t[0] = t[4] = cur_x + wp->m_off; t[1] = t[5] = cur_y; t[2] = t[6] = X0-1 + xsiz*inc_x +wp->m_off; t[3] = t[7] = cur_y+inc_y-1; vro_cpyfm(screen_handle, FM_CLEAR, t, &wp->wi_mf, &wp->wi_mf); if (! scrolled) w_update(wp, FM_COPY, cur_x, cur_y, xsiz * inc_x - cur_x, inc_y); state = S_NORMAL; break; case 'L': /* Insert Line */ case 'M': /* Delete Line */ if (count == 0) { count = 1; /* Look ahead for contiguous insert/delete line operations */ while (*ptr == '\033' && ptr[1] == ch) { ptr +=2; count ++; } } if (ch == 'L') scrolldn(wp, cur_y/inc_y, ysiz-(cur_y-wp->top_y+Y0)/inc_y-count, count); else scrollup(wp, cur_y / inc_y, ysiz - (cur_y - wp->top_y + Y0)/inc_y - count, count); if (! scrolled) w_update(wp, FM_COPY, X0, cur_y, xsiz * inc_x, ysiz * inc_y - cur_y + wp->top_y - Y0); state = S_NORMAL; break; case 'h': /* Insert Mode */ wp->insmode = 1; state = S_NORMAL; break; case 'i': /* End Insert */ wp->insmode = 0; state = S_NORMAL; break; case 'a': /* Delete Character */ t[0] = cur_x + inc_x + wp->m_off; t[1] = t[5] = cur_y; t[2] = X0 - 1 + xsiz * inc_x + wp->m_off; t[3] = t[7] = cur_y+inc_y - 1; t[4] = t[0] - inc_x; t[6] = t[2] - inc_x; vro_cpyfm(screen_handle, FM_COPY, t, &wp->wi_mf, &wp->wi_mf); t[0] = t[4] = X0 + (xsiz - 1) * inc_x + wp->m_off; t[2] = t[6] = t[0] + inc_x - 1; vro_cpyfm(screen_handle, FM_CLEAR, t, &wp->wi_mf, &wp->wi_mf); if (! scrolled) w_update(wp, FM_COPY, cur_x, cur_y, xsiz * inc_x - (cur_x - X0), inc_y); state = S_NORMAL; break; case 'v': /* clear discard mode */ wp->discard = 0; state = S_NORMAL; break; case 'w': /* set discard mode */ wp->discard = 1; state = S_NORMAL; break; case 'Y': /* Cursor Movement */ state = S_ESC1; break; case 'p': /* Enter Inverse */ wp->inverse = 1; state = S_NORMAL; break; case 'q': /* Exit Inverse */ wp->inverse = 0; state = S_NORMAL; break; case 'S': /* Change Status Line */ state = S_STATUS; wp->nuptr = 0; break; default: /* Unknown escape sequence */ state = S_NORMAL; break; } break; case S_FG: wp->fgbg[0] = ch & (ncolors-1); state = S_NORMAL; scrolled = 1; /* force a hard update */ break; case S_BG: wp->fgbg[1] = ch & (ncolors-1); state = S_NORMAL; scrolled = 1; /* force a hard update */ break; case S_ESC1: /* get line number */ if (ch < ' ' || ch >= ' ' + ysiz) ch = ' '; f_y = cur_y = (ch-' ')*inc_y + wp->top_y; state = S_ESC3; break; case S_ESC3: /* get column number */ if (ch < ' ' || ch >= ' ' + xsiz) ch = ' '; f_x = cur_x = (ch-' ')*inc_x +X0; state = S_NORMAL; break; case S_STATUS: if (ch == '\r') { wp->nuname[wp->nuptr] = '\0'; w_rename(wp, wp->nuname); state = S_NORMAL; } else if (wp->nuptr < 72) { wp->nuname[wp->nuptr++] = ch; } break; } /* end switch on state */ if (scrolled >= MAXSCROLLED) { if (wp->top_y != Y0) { scrollup(wp, 0, ysiz, wp->top_y/inc_y); wp->top_y = Y0; f_y = cur_y = Y0 + (ysiz - 1) * inc_y; } w_redraw(wp, FM_COPY, wp->x, wp->y, wp->w, wp->h); scrolled = 0; } } /* end while loop for each character */ /* * "scrolled" is true if you need to do a hard update, where multiple * lines may have changed. This used to actually align the virtual * screen with the physical screen only when scrolled >= MAXSCROLLED, but * this meant that seven lines out of eight got hard updates for every * char when typing on a scrolling TTY. So I align them every time. */ if (scrolled) { if (wp->top_y != Y0) { scrollup(wp, 0, ysiz, wp->top_y/inc_y); wp->top_y = Y0; cur_y = Y0 + (ysiz - 1) * inc_y; } w_redraw(wp, FM_COPY, wp->x, wp->y, wp->w, wp->h); } else { if (f_mod) { if (!wp->insmode) w_update(wp, FM_COPY, f_x, f_y, cur_x - f_x, inc_y); else w_update(wp, FM_COPY, f_x, f_y, xsiz * inc_x-f_x, inc_y); } } wp->cur_x = cur_x; wp->cur_y = cur_y; wp->state = state; w_flash(wp, 1); } void lineerase(wp, first, last) register struct wi_str *wp; int first, last; { register short *p; register long *lp; long count; long linespace = wp->wi_mf.wwords*wp->font->inc_y; p = wp->wi_mf.ptr + first*linespace + Y0*wp->wi_mf.wwords - 1; count = (last-first+1)*linespace; lp = (long *)p; while (count > 7) { *lp++ = 0; *lp++ = 0; *lp++ = 0; *lp++ = 0; count -= 8; } p = (short *)lp; while (--count >= 0) *++p = 0; } void scrollup(wp, first, nlines, amount) register struct wi_str *wp; int first, nlines, amount; { register short *p1, *p2; register long *lp1, *lp2; register long count; int linespace = wp->wi_mf.wwords*wp->font->inc_y; p1 = wp->wi_mf.ptr + first*linespace + Y0*wp->wi_mf.wwords; p2 = p1 + linespace * amount; count = (long)(nlines)*linespace; lp1 = (long *)p1; lp2 = (long *)p2; while (count > 15) { *lp1++ = *lp2++; *lp1++ = *lp2++; *lp1++ = *lp2++; *lp1++ = *lp2++; *lp1++ = *lp2++; *lp1++ = *lp2++; *lp1++ = *lp2++; *lp1++ = *lp2++; count -= 16; } p1 = (short *)lp1; p2 = (short *)lp2; while (--count >= 0) *(p1++) = *(p2++); count = linespace * amount; lp1 = (long *)p1; while (count > 7) { *lp1++ = 0; *lp1++ = 0; *lp1++ = 0; *lp1++ = 0; count -= 8; } p1 = (short *)lp1; while (--count >= 0) *(p1++) = 0; } void scrolldn(wp, first, nlines, amount) register struct wi_str *wp; int first, nlines, amount; { register short *p1, *p2; register long *lp1, *lp2; register long count; long linespace = wp->wi_mf.wwords*wp->font->inc_y; p1 = wp->wi_mf.ptr + (nlines+first+amount)*linespace + Y0*wp->wi_mf.wwords; p2 = p1 - linespace * amount; count = (long)(nlines)*linespace; lp2 = (long *)p2; lp1 = (long *)p1; while (count > 15) { *--lp1 = *--lp2; *--lp1 = *--lp2; *--lp1 = *--lp2; *--lp1 = *--lp2; *--lp1 = *--lp2; *--lp1 = *--lp2; *--lp1 = *--lp2; *--lp1 = *--lp2; count -= 16; } p1 = (short *)lp1; p2 = (short *)lp2; while (--count >= 0) *--p1 = *--p2; count = linespace * amount; lp1 = (long *)p1; while (count > 7) { *--lp1 = 0L; *--lp1 = 0L; *--lp1 = 0L; *--lp1 = 0L; count -= 8; } p1 = (short *)lp1; while (--count >= 0) *--p1 = 0; }