/* @(#)ll_refresh.c 1.1 (1.22) */ #include "curses.ext" extern int InputPending; extern int outchcount; extern int *context; int didntdobotright; /* writechars didn't output char in bot right corner */ /* * Optimally make the screen (which currently looks like SP->cur_body) * look like SP->std_body. If use_idl is 1, this routine will call * out all its horses, including some code to figure out * how to use insert/delete line. If use_idl is 0, or if the terminal * does not have insert/delete line, a simpler scheme will * be used, and the insert/delete line features of the terminal will not * be used. * * While the original intent of this parameter was speed (insert/delete * line was slow) the parameter currently is there to avoid annoying * the user with unnecessary insert/delete lines. */ int _ll_refresh (use_idl) int use_idl; { register int n, i, j; register struct line *dln, *pln; struct line *_line_alloc(); #ifdef DEBUG if(outf) fprintf(outf, "_ll_refresh(%d)\n", use_idl); if(outf) fprintf(outf, "phys cursor at (%d,%d), want cursor at (%d,%d)\n", SP->phys_y, SP->phys_x, SP->virt_y, SP->virt_x); #endif DEBUG outchcount = 0; #ifdef FIONREAD if( SP->check_fd >= 0 ) { ioctl (SP->check_fd, FIONREAD, &InputPending); } else { InputPending = 0; } if( InputPending ) { #ifdef DEBUG if (outf) fprintf(outf, "InputPending %d, aborted ll_refresh at start\n", InputPending); #endif DEBUG return 0; } #endif FIONREAD #ifdef NONSTANDARD input_wait(); #endif NONSTANDARD #ifdef DEBUG if (outf) fprintf(outf, "virt cursor at y=%d, x=%d, length %d, length-1 %d\n", SP->virt_y, SP->virt_x, SP->std_body[SP->virt_y+1]->length, SP->std_body[SP->virt_y]->length); #endif DEBUG if( SP->virt_y >= 0 && SP->std_body[SP->virt_y+1]->length < SP->virt_x ) { SP->std_body[SP->virt_y+1]->length = SP->virt_x >= columns ? columns : SP->virt_x; } /* Get rid of trailing blanks on all lines */ for( n = 1; n <= lines; n++ ) { dln = SP->std_body[n]; pln = SP->cur_body[n]; if( dln && dln != pln ) { register chtype *p; if( i = dln->length ) { p = dln->body + i; while( *--p == ' ' && --i > 0 ) ; dln->length = i; } } if( pln ) { register chtype *p; if( i = pln->length ) { p = pln->body + i; while( *--p == ' ' && --i > 0 ) ; pln->length = i; } } } if( magic_cookie_glitch > 0 ) _toss_cookies(); #ifdef DEBUG if(outf) fprintf(outf, "what we have:\n"); for( i=1; i<=lines; i++ ) { if(outf) fprintf(outf, "%8x: ", SP->cur_body[i]); if( SP->cur_body[i] == NULL ) { if(outf) fprintf(outf, "()\n"); } else { if(outf) fprintf(outf, "%4d ", SP->cur_body[i]->length); for( j=0; j<SP->cur_body[i]->length; j++ ) { n = SP->cur_body[i]->body[j]; if( n & A_ATTRIBUTES ) { putc('\'', outf); } n &= 0177; if(outf) fprintf(outf, "%c", n>=' ' ? n : '.'); } if(outf) fprintf(outf, "\n"); } } if(outf) fprintf(outf, "what we want:\n"); for (i=1; i<=lines; i++) { if(outf) fprintf(outf, "%8x: ", SP->std_body[i]); if (SP->std_body[i] == NULL) { if(outf) fprintf(outf, "()\n"); } else { if(outf) fprintf(outf, "%4d ", SP->std_body[i]->length); for (j=0; j<SP->std_body[i]->length; j++) { n = SP->std_body[i]->body[j]; if (n & A_ATTRIBUTES) { putc('\'', outf); } n &= 0177; if(outf) fprintf(outf, "%c", n>=' ' ? n : '.'); } if(outf) fprintf(outf, "\n"); } } if(outf) fprintf(outf, "----\n"); if(outf) fflush(outf); #endif DEBUG SP->check_input = SP->baud / 2400; if (SP->doclear) { #ifdef DEBUG if(outf) fprintf(outf, "SP->doclear, clearing screen\n"); #endif _reset(); SP->doclear = 0; for( n = 0; n <= lines; n++ ) { if( SP->cur_body[n] != SP->std_body[n] ) { _line_free( SP->cur_body[n] ); } SP->cur_body[n] = 0; } } /* Choose between two updating algorithms. */ if( use_idl && _cost(ilfixed) < INFINITY ) { #ifdef DEBUG if(outf) fprintf(outf, "use_idl\n"); #endif for( n = 1; n <= lines; n++ ) { if( SP->cur_body[n] == 0 ) { SP->cur_body[n] = _line_alloc(); } if( SP->std_body[n] == 0 ) { SP->std_body[n] = SP->cur_body[n]; } else { _comphash( SP->std_body[n] ); } _comphash( SP->cur_body[n] ); } /* * Count number of matches if we scroll 1 line and if we * don't scroll at all. This is primarily useful for the * case where we scroll the whole screen. Scrolling a portion * of the screen will be handled by the ins/del line routines, * although a special case here might buy some CPU speed. */ for( i=1,n=0,j=0; i<lines; i++ ) { if( SP->cur_body[i+1]->hash == SP->std_body[i]->hash ) n++; if( SP->cur_body[i]->hash == SP->std_body[i]->hash ) j++; } if( n > lines-3 && n > j ) { _window(0, lines-1, 0, columns-1); _scrollf(1); _line_free(SP->cur_body[1]); for( i=1; i<lines; i++ ) { /* Copy line with two references since they * are no longer the same row on screen. */ if( SP->cur_body[i+1] == SP->std_body[i+1] ) { struct line *p; int l; chtype *b1, *b2; p = _line_alloc (); p->length=l=SP->cur_body[i+1]->length; p->hash = SP->cur_body[i+1]->hash; b1 = &(p->body[0]); b2 = &(SP->cur_body[i+1]->body[0]); for( ; l>0; l-- ) { *b1++ = *b2++; } SP->std_body[i+1] = p; } SP->cur_body[i] = SP->cur_body[i+1]; } SP->cur_body[lines] = _line_alloc(); } i = 1; /* * Break the screen (from 1 to lines) into clumps of * lines that are different. Thus we ignore the ones that * are identical. */ for( ;; ) { while( i<=lines && SP->cur_body[i]==SP->std_body[i] ) { i++; } if( i > lines ) { break; } for( j=i; j <= lines && SP->cur_body[j] != SP->std_body[j]; j++) ; j--; #ifdef DEBUG if(outf) fprintf(outf, "window from %d to %d\n", i, j); #endif /* i thru j is a window of different lines. */ if( i == j ) { _id_char(SP->cur_body[i], SP->std_body[i], i-1); if( SP->cur_body[i] != SP->std_body[i] ) { _line_free (SP->cur_body[i]); } SP->cur_body[i] = SP->std_body[i]; } else { _window(i-1, j-1, 0, columns-1); _setwind(); /* Force action for moves, etc */ _id_line(i, j); } i = j+1; } } else /* fast update */ { #ifdef DEBUG if(outf) fprintf(outf, "Fast Update, lines %d\n", lines); #endif _window(0, lines-1, 0, columns-1); _setwind(); /* Force action for moves, etc */ for( n = 1; n <= lines; n++ ) if( SP->std_body[n] != SP->cur_body[n] ) { _id_char( SP->cur_body[n],SP->std_body[n],n-1 ); if( SP->cur_body[n] != SP->std_body[n] ) { _line_free (SP->cur_body[n]); } SP->cur_body[n] = SP->std_body[n]; } } /* * Didn't output char in bottom right corner of screen. * Remember this fact so that next time when it's higher * on the screen, we'll fix it up. */ if( didntdobotright ) { int holdvx, holdvy; #ifdef DEBUG if (outf) fprintf(outf, "didntdobotright so setting SP->cur_body[%d]->body[%d] from '%c' to space.\n", lines, columns-1, SP->cur_body[lines]->body[columns-1]); #endif holdvx = SP->virt_x; holdvy = SP->virt_y; /* * This code in effect marks the last line dirty * so that the next time it will get fixed. It also * splits the line back into virt/phys so we don't * clobber the virtual part too. */ _ll_move(lines-1, columns-1); SP->cur_body[lines]->body[columns-1] = ' '; didntdobotright = 0; /* Now restore the cursor we clobbered. */ _ll_move(holdvy, holdvx); } _hlmode(0); _sethl(); #ifdef DEBUG if(outf) fprintf(outf, "at end, phys SP->curptr at (%d,%d), want SP->curptr at (%d,%d)\n", SP->phys_y, SP->phys_x, SP->virt_y, SP->virt_x); #endif DEBUG #ifdef notdef if(magic_cookie_glitch > 0) _fixcursor(); #endif notdef if( !InputPending && SP->virt_x >= 0 && SP->virt_y >= 0 ) { _pos (SP->virt_y, SP->virt_x); } __cflush(); #ifdef DEBUG if(outf) fprintf(outf, "end of _ll_refresh, InputPending %d\n", InputPending); if(outf) fflush(outf); #endif DEBUG return outchcount; } /* * This routine is only needed on terminals with the "magic cookie" * effect. The problem is that the designers of * these terminals didn't allocate 16 bits for * each character (7 for the character and 9 for attributes) but instead * created some reserved "magic cookie" characters to tell the scan * routine "you should change attributes now". This would be fine except * that these cookies take up a space in memory, and usually display as a * blank. This makes it impossible to display what the user really * wanted, if he is using attributes for underlining, bold, etc. Such * terminals include the Teleray 1061, TVI 912 and 950, Teletype * DataSpeed 40, and Adds Regent 40. * * One approach to this problem is to make everybody pay the price of * this effect, forcing the programmer to allocate a blank space * when attributes are changed. This works cleanly but I consider it * unacceptable. * * My approach is to simulate what the programmer (who wasn't thinking * about these terminals) wanted as closely as possible. If there * is a desired blank in there, we use that slot. If not, we shove the * rest of the line to the right one space. (When several attributes * are changed on one line, this can result in losing several characters * from the right of the line.) * * This routine looks for places in SP->std_body where shoving to the * right is needed, and does the required shoving. */ static _toss_cookies() { register int i, j, len; register struct line *dsi; register chtype *b; #ifdef DEBUG if(outf) fprintf(outf, "_toss_cookies\n"); #endif for( i=1; i<=lines; i++ ) { dsi = SP->std_body[i]; if( dsi && dsi != SP->cur_body[i] ) { len = dsi->length; b = dsi->body; for( j=0; j<len; j++ ) { if( b[j]&A_ATTRIBUTES ) { #ifdef DEBUG if(outf) fprintf(outf, "_shove, line %d, char %d, val %o\n", i, j, b[j]); #endif dsi->length = _shove(b, len, i); break; } } } } }