/* This file holds the functions for manipulating video memory */ #include #include #include #include "video.h" #include "terminal.h" /* This function returns a pointer to a video memory area of ints. Integers are used to encode both the characters and the flags. If this function fails, it should be a fatal error. Allocated memory is not freed if the function fails. */ int **alloc_video(rows, cols) int rows; int cols; { int **videomem; int i, j; /* Allocate row pointers */ if ( (videomem=(int **)malloc(rows*sizeof(int *))) == NULL ) return(NULL); /* Allocate the columns for each row */ for ( i=0; ix=0; for ( i=win->rows, ni=rows; i && ni; --i, --ni ) { if ( win->cursor.x == i ) { if ( (newcursor->x=(i+rows-win->rows)) < 1 ) newcursor->x=1; } for ( j=0, nj=0; (jcols) && (njvideomem[i-1][j]; } if ( ! newcursor->x ) /* We never reached the old cursor */ newcursor->x=1; newcursor->y=(win->cursor.y > cols ? cols : win->cursor.y); } /* This function adds a character to the video memory at the cursor position */ void add_video(win, c) window *win; char c; { win->videomem[win->cursor.x - 1][win->cursor.y - 1] = (int)c; win->videomem[win->cursor.x - 1][win->cursor.y - 1] |= (((int)win->textattr)<<8); } /* This function returns a character from video at a specific position */ int get_video(win, x, y) window *win; int x, y; { return(win->videomem[x-1][y-1]); } /* This function sets a character position in video memory */ void put_video(c, win, x, y) int c; window *win; int x, y; { win->videomem[x-1][y-1]=c; } /* This function returns the array index of the end of the specified line in the specified window. lineno should start as 1 for the first line. */ static int video_eol(win, lineno) window *win; int lineno; { int eol=(-1), j; for ( j=0; jcols; ++j ) { if ( (win->videomem[lineno-1][j]&0xFF) != 0 ) eol=j; } ++eol; return(eol); } /* This function copies a specified section of video memory to a buffer */ /* x1 is the first line, x2 is the second line, y1 is the y on the first line, and y2 is the y on the last line. */ void getsel_video(win, buf, maxlen, x1, x2, y1, y2) window *win; char *buf; int maxlen; int x1, x2; int y1, y2; { int l=0, i, j, eol, eos=0; --maxlen; /* Account for trailing null */ for ( i=(x1-1); (ivideomem[i][j]&0xFF) == '\0' ) *(buf++) = ' '; else *(buf++) = (win->videomem[i][j]&0xFF); ++l; } if ( l= eol ) { *(buf++) = '\r'; ++l; } } *buf='\0'; return; } /* This function clears the SELECTED bit in a whole window */ void clrsel_video(win) window *win; { int i, j; for ( i=0; irows; ++i ) { for ( j=0; jcols; ++j ) { if ( ((win->videomem[i][j]>>8)&SELECTED) == SELECTED ) win->videomem[i][j] &= ~(SELECTED<<8); } } } /* This function erases a specified section of video memory */ void erase_video(win, x1, x2, y1, y2) window *win; int x1, x2; int y1, y2; { int i, j; for ( i=(x1-1); ivideomem[i][j] = 0; } return; } /* This function "scrolls" video memory forward */ void scroll_video(win, numlines) window *win; int numlines; { int i, n, *tmp; /* Don't scroll memory if cursor is outside of scroll region */ if ( win->cursor.x > win->scr_lower ) return; /* Otherwise, scroll away! */ for ( i=0; ivideomem[win->scr_upper-1]; for ( n=0; ncols; ++n ) tmp[n]=0; /* Now perform the scroll */ for ( n=(win->scr_upper-1); n<(win->scr_lower-1); ++n ) win->videomem[n]=win->videomem[n+1]; win->videomem[n]=tmp; } /* That's it! */ return; } /* This function "scrolls" video memory backward */ void revscroll_video(win, numlines) window *win; int numlines; { int i, n, *tmp; /* Don't scroll memory if cursor is outside of scroll region */ if ( win->cursor.x < win->scr_upper ) return; /* Otherwise, scroll away! */ for ( i=0; ivideomem[win->scr_lower-1]; for ( n=0; ncols; ++n ) tmp[n]=0; /* Now perform the scroll */ for ( n=(win->scr_lower-1); n>(win->scr_upper-1); --n ) win->videomem[n]=win->videomem[n-1]; win->videomem[n]=tmp; } /* That's it! */ return; } /* This function inserts nulls in a line, shifting everything right */ void rshift_video(win, numcols) window *win; int numcols; { int i; for ( i=(win->cols-1); i > (win->cursor.y-1); --i ) { if ( (i-numcols) >= 0 ) win->videomem[win->cursor.x-1][i] = win->videomem[win->cursor.x-1][i-numcols]; else win->videomem[win->cursor.x-1][i] = 0; } } int check_attr(pixel, lastattr, currattr) int pixel; int lastattr; unsigned char *currattr; { unsigned char simplepixel, lastpixel; unsigned char change; unsigned char selected, reversed; /* Set the simplepixel REVERSE bit if SELECTED ^ REVERSE */ simplepixel = ((pixel>>8)&(~SELECTED)&(~REVERSE)); selected = ( ((pixel>>8)&(~SELECTED)) ? 1 : 0 ); reversed = ( ((pixel>>8)&(~REVERSE)) ? 1 : 0 ); if ( selected ^ reversed ) simplepixel |= REVERSE; /* Set the lastpixel REVERSE bit if SELECTED ^ REVERSE */ lastpixel = ((lastattr>>8)&(~SELECTED)&(~REVERSE)); selected = ( ((lastattr>>8)&(~SELECTED)) ? 1 : 0 ); reversed = ( ((lastattr>>8)&(~REVERSE)) ? 1 : 0 ); if ( selected ^ reversed ) lastpixel |= REVERSE; /* Thanks to Dan Dorough for the XOR code */ checkchange: change = (lastpixel ^ simplepixel); if ( change ) { if ( change&REVERSE ) { if ( (*currattr)&REVERSE ) { #define GOTO_HACK /* vt_reverse(0) doesn't work on xterms :-( */ #ifdef GOTO_HACK /* This goto hack resets all current attributes */ vt_resetattr(); *currattr &= ~REVERSE; simplepixel=0; lastpixel &= (~REVERSE); goto checkchange; #else /* ideal code */ vt_reverse(0); *currattr &= ~REVERSE; #endif } else { vt_reverse(1); *currattr |= REVERSE; } } if ( change&BOLD ) { if ( (*currattr)&BOLD ) { vt_bold(0); *currattr &= ~BOLD; } else { vt_bold(1); *currattr |= BOLD; } } if ( change&UNDERLINE ) { if ( (*currattr)&UNDERLINE ) { vt_underline(0); *currattr &= ~UNDERLINE; } else { vt_underline(1); *currattr |= UNDERLINE; } } if ( change&BLINK ) { if ( (*currattr)&BLINK ) { vt_blink(0); *currattr &= ~BLINK; } else { vt_blink(1); *currattr |= BLINK; } } } return(pixel); } void paint_video(win) window *win; { unsigned char on=NORMAL; int i, j, oldattr=0; vt_setscroll(0,0); vt_resetattr(); vt_goto(1+win->row_offset, 1); for ( i=0; irows; ++i ) { for ( j=0; jcols; ++j ) { if ( win->videomem[i][j]&0xFF ) { oldattr=check_attr(win->videomem[i][j], oldattr, &on); printf("%c", (win->videomem[i][j]&0xFF)); } else { oldattr=0; if ( on != NORMAL ) { vt_resetattr(); on=NORMAL; } printf(" "); } } printf("\r"); vt_down(1); /* This shouldn't cause scroll */ } vt_setscroll(win->scr_upper+win->row_offset, win->scr_lower+win->row_offset); vt_goto(win->cursor.x+win->row_offset, win->cursor.y); vt_update(); }