/* * Initialize the data structures used by the display code. The edge vectors * used to access the screens are set up. The operating system's terminal I/O * channel is set up. All the other things get initialized at compile time. * The original window has "WFCHG" set, so that it will get completely * redrawn on the first call to "update". */ void vtinit(void) { int i; struct video *vp; TTopen(); /* open the screen */ TTkopen(); /* open the keyboard */ TTrev(FALSE); vscreen = xmalloc(term.t_mrow * sizeof(struct video *)); #if MEMMAP == 0 || SCROLLCODE pscreen = xmalloc(term.t_mrow * sizeof(struct video *)); #endif for (i = 0; i < term.t_mrow; ++i) { vp = xmalloc(sizeof(struct video) + term.t_mcol*4); vp->v_flag = 0; #if COLOR vp->v_rfcolor = 7; vp->v_rbcolor = 0; #endif vscreen[i] = vp; #if MEMMAP == 0 || SCROLLCODE vp = xmalloc(sizeof(struct video) + term.t_mcol*4); vp->v_flag = 0; pscreen[i] = vp; #endif } }
// Initialize the data structures used by the display code. The edge vectors used to access the screens are set up. The // operating system's terminal I/O channel is set up. All the other things get initialized at compile time. The original // window has "WFCHGD" set, so that it will get completely redrawn on the first call to "update". Return status. int vtinit(void) { int i; Video *vvp,*pvp; static char myname[] = "vtinit"; if(TTopen() != SUCCESS || // Open the screen. TTkopen() != SUCCESS || // Open the keyboard. TTrev(false) != SUCCESS) return rc.status; // Allocate the virtual screen and physical shadow screen arrays (of pointers). if((vscreen = (Video **) malloc(term.t_mrow * sizeof(Video *))) == NULL || (pscreen = (Video **) malloc(term.t_mrow * sizeof(Video *))) == NULL) return rcset(PANIC,0,text94,myname); // "%s(): Out of memory!" // For every line in the display terminal. i = 0; do { // Allocate a virtual screen line and physical shadow screen line. if((vvp = (Video *) malloc(sizeof(Video) + term.t_mcol)) == NULL || (pvp = (Video *) malloc(sizeof(Video) + term.t_mcol)) == NULL) return rcset(PANIC,0,text94,myname); // "%s(): Out of memory!" // Initialize virtual line and save in line array. vvp->v_flags = 0; // Init change flags. vvp->v_left = FARRIGHT; // Init requested rev video boundaries. vvp->v_right = 0; #if COLOR vvp->v_rfcolor = 7; // Init fore/background colors. vvp->v_rbcolor = 0; #endif vscreen[i] = vvp; // Initialize physical line and save in line array. pvp->v_flags = VFNEW; pvp->v_left = FARRIGHT; pvp->v_right = 0; pscreen[i] = pvp; } while(++i < term.t_mrow); return rc.status; }
void vtinit() { register int i; register VIDEO *vp; TTopen(); /* open the screen */ TTkopen(); /* open the keyboard */ TTrev(FALSE); vscreen = (VIDEO **) malloc(term.t_mrow*sizeof(VIDEO *)); if (vscreen == NULL) exit(1); #if MEMMAP == 0 pscreen = (VIDEO **) malloc(term.t_mrow*sizeof(VIDEO *)); if (pscreen == NULL) exit(1); #endif for (i = 0; i < term.t_mrow; ++i) { vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_mcol); if (vp == NULL) exit(1); vp->v_flag = 0; #if COLOR vp->v_rfcolor = 7; vp->v_rbcolor = 0; #endif vscreen[i] = vp; #if MEMMAP == 0 vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_mcol); if (vp == NULL) exit(1); vp->v_flag = 0; pscreen[i] = vp; #endif } }
/* * updateline() * * int row; row of screen to update * struct video *vp1; virtual screen image * struct video *vp2; physical screen image */ static int updateline(int row, struct video *vp1, struct video *vp2) { #if RAINBOW /* UPDATELINE specific code for the DEC rainbow 100 micro */ unicode_t *cp1; unicode_t *cp2; int nch; /* since we don't know how to make the rainbow do this, turn it off */ flags &= (~VFREV & ~VFREQ); cp1 = &vp1->v_text[0]; /* Use fast video. */ cp2 = &vp2->v_text[0]; putline(row + 1, 1, cp1); nch = term.t_ncol; do { *cp2 = *cp1; ++cp2; ++cp1; } while (--nch); *flags &= ~VFCHG; #else /* UPDATELINE code for all other versions */ unicode_t *cp1; unicode_t *cp2; unicode_t *cp3; unicode_t *cp4; unicode_t *cp5; int nbflag; /* non-blanks to the right flag? */ int rev; /* reverse video flag */ int req; /* reverse video request flag */ /* set up pointers to virtual and physical lines */ cp1 = &vp1->v_text[0]; cp2 = &vp2->v_text[0]; #if COLOR TTforg(vp1->v_rfcolor); TTbacg(vp1->v_rbcolor); #endif #if REVSTA | COLOR /* if we need to change the reverse video status of the current line, we need to re-write the entire line */ rev = (vp1->v_flag & VFREV) == VFREV; req = (vp1->v_flag & VFREQ) == VFREQ; if ((rev != req) #if COLOR || (vp1->v_fcolor != vp1->v_rfcolor) || (vp1->v_bcolor != vp1->v_rbcolor) #endif ) { movecursor(row, 0); /* Go to start of line. */ /* set rev video if needed */ if (rev != req) (*term.t_rev) (req); /* scan through the line and dump it to the screen and the virtual screen array */ cp3 = &vp1->v_text[term.t_ncol]; while (cp1 < cp3) { TTputc(*cp1); ++ttcol; *cp2++ = *cp1++; } /* turn rev video off */ if (rev != req) (*term.t_rev) (FALSE); /* update the needed flags */ vp1->v_flag &= ~VFCHG; if (req) vp1->v_flag |= VFREV; else vp1->v_flag &= ~VFREV; #if COLOR vp1->v_fcolor = vp1->v_rfcolor; vp1->v_bcolor = vp1->v_rbcolor; #endif return TRUE; } #endif /* advance past any common chars at the left */ while (cp1 != &vp1->v_text[term.t_ncol] && cp1[0] == cp2[0]) { ++cp1; ++cp2; } /* This can still happen, even though we only call this routine on changed * lines. A hard update is always done when a line splits, a massive * change is done, or a buffer is displayed twice. This optimizes out most * of the excess updating. A lot of computes are used, but these tend to * be hard operations that do a lot of update, so I don't really care. */ /* if both lines are the same, no update needs to be done */ if (cp1 == &vp1->v_text[term.t_ncol]) { vp1->v_flag &= ~VFCHG; /* flag this line is changed */ return TRUE; } /* find out if there is a match on the right */ nbflag = FALSE; cp3 = &vp1->v_text[term.t_ncol]; cp4 = &vp2->v_text[term.t_ncol]; while (cp3[-1] == cp4[-1]) { --cp3; --cp4; if (cp3[0] != ' ') /* Note if any nonblank */ nbflag = TRUE; /* in right match. */ } cp5 = cp3; /* Erase to EOL ? */ if (nbflag == FALSE && eolexist == TRUE && (req != TRUE)) { while (cp5 != cp1 && cp5[-1] == ' ') --cp5; if (cp3 - cp5 <= 3) /* Use only if erase is */ cp5 = cp3; /* fewer characters. */ } movecursor(row, cp1 - &vp1->v_text[0]); /* Go to start of line. */ #if REVSTA TTrev(rev); #endif while (cp1 != cp5) { /* Ordinary. */ TTputc(*cp1); ++ttcol; *cp2++ = *cp1++; } if (cp5 != cp3) { /* Erase. */ TTeeol(); while (cp1 != cp3) *cp2++ = *cp1++; } #if REVSTA TTrev(FALSE); #endif vp1->v_flag &= ~VFCHG; /* flag this line as updated */ return TRUE; #endif }
// Update a single line on the physical screen, given row, virtual screen image, and physical screen image. This does not know // how to use insert or delete character sequences; we are using VT52 functionality. Update the physical row and column // variables. It does try to exploit erase to end of line. Return status. static int pupd_line(int row,Video *vp,Video *pp) { char *vir_left; // Left pointer to virtual line. char *phy_left; // Left pointer to physical line. char *vir_right; // Right pointer to virtual line. char *phy_right; // Right pointer to physical line. int rev_left; // Leftmost reversed char index. int rev_right; // Rightmost reversed char index. char *left_blank; // Left-most trailing blank. int non_blanks; // Non-blanks to the right flag. int update_column; // Update column. int old_rev_state = false; // Reverse video states. int new_rev_state; // Set up pointers to virtual and physical lines. vir_left = vp->v_text; vir_right = vp->v_text + term.t_ncol; phy_left = pp->v_text; phy_right = pp->v_text + term.t_ncol; update_column = 0; rev_left = FARRIGHT; rev_right = 0; non_blanks = true; // If this is a legitimate line to optimize. if(!(pp->v_flags & VFNEW)) { // Advance past any common chars at the left. while(vir_left != vp->v_text + term.t_ncol && vir_left[0] == phy_left[0]) { ++vir_left; ++update_column; ++phy_left; } // Advance past any common chars at the right. non_blanks = false; while(vir_right[-1] == phy_right[-1] && vir_right >= vir_left) { --vir_right; --phy_right; // Note if any nonblank in right match. if(vir_right[0] != ' ') non_blanks = true; } } #if COLOR // New line color? if(vp->v_rfcolor != vp->v_fcolor || vp->v_rbcolor != vp->v_bcolor) { vp->v_fcolor = vp->v_rfcolor; vp->v_bcolor = vp->v_rbcolor; vp->v_flags &= ~VFCOLOR; vir_left = vp->v_text; vir_right = vp->v_text + term.t_ncol; phy_left = pp->v_text; phy_right = pp->v_text + term.t_ncol; update_column = 0; } if(TTforg(vp->v_fcolor) != SUCCESS || TTbacg(vp->v_bcolor) != SUCCESS) return rc.status; #endif // Reverse video changes? if(vp->v_left != pp->v_left || vp->v_right != pp->v_right) { // Adjust leftmost edge. if(vp->v_left < pp->v_left) rev_left = vp->v_left; else rev_left = pp->v_left; pp->v_left = vp->v_left; if(rev_left < update_column) { vir_left = vp->v_text + rev_left; phy_left = pp->v_text + rev_left; update_column = rev_left; } // Adjust rightmost edge. if(vp->v_right > pp->v_right) rev_right = vp->v_right; else rev_right = pp->v_right; pp->v_right = vp->v_right; if(vp->v_text + rev_right > vir_right) { vir_right = vp->v_text + rev_right; phy_right = pp->v_text + rev_right; } } else { rev_left = vp->v_left; rev_right = vp->v_right; } // If both lines are the same, no update needs to be done. if(!(pp->v_flags & VFNEW) && vir_left > vir_right) { vp->v_flags &= ~VFCHGD; // Clear changed flag. return rc.status; } left_blank = vir_right; // Erase to EOL? if(non_blanks == false && (opflags & OPHAVEEOL)) { while(left_blank != vir_left && left_blank[-1] == ' ') --left_blank; if(vir_right - left_blank <= 3) // Use only if erase is > 3 characters. left_blank = vir_right; } // Move to the beginning of the text to update. if(movecursor(row,update_column) != SUCCESS) return rc.status; while(vir_left != left_blank) { // Ordinary. // Are we in a reverse video field? if(pp->v_left <= update_column && update_column < pp->v_right) new_rev_state = true; else new_rev_state = false; // If moving in or out of reverse video, change it. if(new_rev_state != old_rev_state) { if(TTrev(new_rev_state) != SUCCESS) return rc.status; old_rev_state = new_rev_state; } // Output the next character. if(TTputc(*vir_left) != SUCCESS) return rc.status; ++update_column; *phy_left++ = *vir_left++; } if(left_blank != vir_right) { // Erase. // Are we in a reverse video field? if(pp->v_left <= update_column && update_column < pp->v_right) new_rev_state = true; else new_rev_state = false; // If moving in or out of reverse video, change it. if(new_rev_state != old_rev_state) { if(TTrev(new_rev_state) != SUCCESS) return rc.status; old_rev_state = new_rev_state; } #if TT_TERMCAP // TERMCAP does not tell us if the current terminal propagates the current attributes to the end of the line // when an erase to end of line sequence is sent. Don't let TERMCAP use EEOL if in a reverse video line! if(new_rev_state == true) while(update_column++ < (int) term.t_ncol) { if(TTputc(' ') != SUCCESS) return rc.status; } else if(TTeeol() != SUCCESS) return rc.status; #else if(TTeeol() != SUCCESS) return rc.status; #endif while(vir_left != vir_right) *phy_left++ = *vir_left++; } vp->v_flags &= ~VFCHGD; // Flag this line as updated. #if COLOR vp->v_flags &= ~VFCOLOR; #endif // Always leave in the default state. if(old_rev_state == true) (void) TTrev(false); return rc.status; }