/* * Reverse scrolls the screen by amount lines, erases top, doesn't alter * cursor position (i.e. cursor moves up amount relative to text). * All done within the scrolling region, of course. * Requires: amount > 0 */ void RevScroll(register TScreen *screen, register int amount) { register int i = screen->bot_marg - screen->top_marg + 1; register int shift; register int bot; register int refreshtop; register int refreshheight; register int scrolltop; register int scrollheight; if(screen->cursor_state) HideCursor(); if (amount > i) amount = i; if(screen->jumpscroll) { if(screen->scroll_amt < 0) { if(-screen->refresh_amt + amount > i) FlushScroll(screen); screen->scroll_amt -= amount; screen->refresh_amt -= amount; } else { if(screen->scroll_amt > 0) FlushScroll(screen); screen->scroll_amt = -amount; screen->refresh_amt = -amount; } } else { shift = -screen->topline; bot = screen->max_row - shift; refreshheight = amount; scrollheight = screen->bot_marg - screen->top_marg - refreshheight + 1; refreshtop = screen->top_marg + shift; scrolltop = refreshtop + refreshheight; if((i = screen->bot_marg - bot) > 0) scrollheight -= i; if((i = screen->top_marg + refreshheight - 1 - bot) > 0) refreshheight -= i; if (screen->multiscroll && amount == 1 && screen->topline == 0 && screen->top_marg == 0 && screen->bot_marg == screen->max_row) { if (screen->incopy < 0 && screen->scrolls == 0) CopyWait(screen); screen->scrolls++; } scrolling_copy_area(screen, scrolltop-amount, scrollheight, -amount); if(refreshheight > 0) { ClearCurBackground(screen, (int) refreshtop * FontHeight(screen) + screen->border, (int) OriginX(screen), (unsigned) refreshheight * FontHeight(screen), (unsigned) Width(screen)); } } ScrnInsertLine(screen, screen->visbuf, screen->bot_marg, screen->top_marg, amount, screen->max_col + 1); }
/* * If cursor not in scrolling region, returns. Else, * inserts n blank lines at the cursor's position. Lines above the * bottom margin are lost. */ void InsertLine (register TScreen *screen, register int n) { register int i; register int shift; register int bot; register int refreshtop; register int refreshheight; register int scrolltop; register int scrollheight; if (screen->cur_row < screen->top_marg || screen->cur_row > screen->bot_marg) return; if(screen->cursor_state) HideCursor(); screen->do_wrap = 0; if (n > (i = screen->bot_marg - screen->cur_row + 1)) n = i; if(screen->jumpscroll) { if(screen->scroll_amt <= 0 && screen->cur_row <= -screen->refresh_amt) { if(-screen->refresh_amt + n > screen->max_row + 1) FlushScroll(screen); screen->scroll_amt -= n; screen->refresh_amt -= n; } else if(screen->scroll_amt) FlushScroll(screen); } if(!screen->scroll_amt) { shift = -screen->topline; bot = screen->max_row - shift; refreshheight = n; scrollheight = screen->bot_marg - screen->cur_row - refreshheight + 1; refreshtop = screen->cur_row + shift; scrolltop = refreshtop + refreshheight; if((i = screen->bot_marg - bot) > 0) scrollheight -= i; if((i = screen->cur_row + refreshheight - 1 - bot) > 0) refreshheight -= i; vertical_copy_area(screen, scrolltop-n, scrollheight, -n); if(refreshheight > 0) { ClearCurBackground(screen, (int) refreshtop * FontHeight(screen) + screen->border, (int) OriginX(screen), (unsigned) refreshheight * FontHeight(screen), (unsigned) Width(screen)); } } ScrnInsertLine(screen, screen->visbuf, screen->bot_marg, screen->cur_row, n, screen->max_col + 1); }
/* * Clear from cursor position to end of display, inclusive. */ static void ClearBelow (register TScreen *screen) { ClearRight(screen, -1); if (screen->protected_mode != OFF_PROTECT) { register int row; for (row = screen->cur_row + 1; row <= screen->max_row; row++) ClearInLine(screen, row, 0, screen->max_col + 1); } else { register int top; if((top = screen->cur_row - screen->topline) <= screen->max_row) { if(screen->scroll_amt) FlushScroll(screen); if(++top <= screen->max_row) { ClearCurBackground(screen, top * FontHeight(screen) + screen->border, OriginX(screen), (screen->max_row - top + 1) * FontHeight(screen), Width(screen)); } } ClearBufRows(screen, screen->cur_row + 1, screen->max_row); } }
/* * Clear from cursor position to beginning of display, inclusive. */ static void ClearAbove (register TScreen *screen) { if (screen->protected_mode != OFF_PROTECT) { register int row; for (row = 0; row <= screen->max_row; row++) ClearInLine(screen, row, 0, screen->max_col + 1); } else { register int top, height; if(screen->cursor_state) HideCursor(); if((top = -screen->topline) <= screen->max_row) { if(screen->scroll_amt) FlushScroll(screen); if((height = screen->cur_row + top) > screen->max_row) height = screen->max_row; if((height -= top) > 0) { ClearCurBackground(screen, top * FontHeight(screen) + screen->border, OriginX(screen), height * FontHeight(screen), Width(screen)); } } ClearBufRows(screen, 0, screen->cur_row - 1); } if(screen->cur_row - screen->topline <= screen->max_row) ClearLeft(screen); }
void xevents(void) { XEvent event; XtInputMask input_mask; register TScreen *screen = &term->screen; if(screen->scroll_amt) FlushScroll(screen); /* * process timeouts, relying on the fact that XtAppProcessEvent * will process the timeout and return without blockng on the * XEvent queue. Other sources i.e. the pty are handled elsewhere * with select(). */ while ((input_mask = XtAppPending(app_con)) & XtIMTimer) XtAppProcessEvent(app_con, XtIMTimer); /* * If there's no XEvents, don't wait around... */ if ((input_mask & XtIMXEvent) != XtIMXEvent) return; do { if (waitingForTrackInfo) return; XtAppNextEvent (app_con, &event); /* * Hack to get around problems with the toolkit throwing away * eventing during the exclusive grab of the menu popup. By * looking at the event ourselves we make sure that we can * do the right thing. */ if(OUR_EVENT(event, EnterNotify)) DoSpecialEnterNotify (&event.xcrossing); else if(OUR_EVENT(event, LeaveNotify)) DoSpecialLeaveNotify (&event.xcrossing); else if ((screen->send_mouse_pos == ANY_EVENT_MOUSE #if OPT_DEC_LOCATOR || screen->send_mouse_pos == DEC_LOCATOR #endif /* OPT_DEC_LOCATOR */ ) && event.xany.type == MotionNotify && event.xcrossing.window == XtWindow(term)) { SendMousePosition((Widget)term, &event); continue; } if (!event.xany.send_event || screen->allowSendEvents || ((event.xany.type != KeyPress) && (event.xany.type != KeyRelease) && (event.xany.type != ButtonPress) && (event.xany.type != ButtonRelease))) XtDispatchEvent(&event); } while ((input_mask = XtAppPending(app_con)) & XtIMXEvent); }
/* * Insert n blanks at the cursor's position, no wraparound */ void InsertChar (register TScreen *screen, register int n) { if(screen->cursor_state) HideCursor(); screen->do_wrap = 0; if(screen->cur_row - screen->topline <= screen->max_row) { if(!AddToRefresh(screen)) { int col = screen->max_col + 1 - n; if(screen->scroll_amt) FlushScroll(screen); #if OPT_DEC_CHRSET if (CSET_DOUBLE(SCRN_BUF_CSETS(screen, screen->cur_row)[0])) { col = (screen->max_col + 1) / 2 - n; } #endif /* * prevent InsertChar from shifting the end of a line over * if it is being appended to */ if (non_blank_line (screen->visbuf, screen->cur_row, screen->cur_col, screen->max_col + 1)) horizontal_copy_area(screen, screen->cur_col, col - screen->cur_col, n); ClearCurBackground( screen, CursorY (screen, screen->cur_row), CurCursorX (screen, screen->cur_row, screen->cur_col), FontHeight(screen), n * CurFontWidth(screen,screen->cur_row)); } } /* adjust screen->buf */ ScrnInsertChar(screen, n, screen->max_col + 1); }
/* * Deletes n chars at the cursor's position, no wraparound. */ void DeleteChar (register TScreen *screen, register int n) { register int width; if(screen->cursor_state) HideCursor(); screen->do_wrap = 0; if (n > (width = screen->max_col + 1 - screen->cur_col)) n = width; if(screen->cur_row - screen->topline <= screen->max_row) { if(!AddToRefresh(screen)) { int col = screen->max_col + 1 - n; if(screen->scroll_amt) FlushScroll(screen); #if OPT_DEC_CHRSET if (CSET_DOUBLE(SCRN_BUF_CSETS(screen, screen->cur_row)[0])) { col = (screen->max_col + 1) / 2 - n; } #endif horizontal_copy_area(screen, screen->cur_col+n, col - screen->cur_col, -n); ClearCurBackground ( screen, CursorY (screen, screen->cur_row), CurCursorX(screen, screen->cur_row, col), FontHeight(screen), n * CurFontWidth(screen,screen->cur_row)); } } /* adjust screen->buf */ ScrnDeleteChar (screen, n, screen->max_col + 1); }
/* * Interpret sixel graphics sequences. * * Resources: * http://en.wikipedia.org/wiki/Sixel * http://vt100.net/docs/vt3xx-gp/chapter14.html * ftp://ftp.cs.utk.edu/pub/shuford/terminal/sixel_graphics_news.txt * ftp://ftp.cs.utk.edu/pub/shuford/terminal/all_about_sixels.txt */ void parse_sixel(XtermWidget xw, ANSI *params, char const *string) { TScreen *screen = TScreenOf(xw); Graphic *graphic; SixelContext context; Char ch; switch (screen->terminal_id) { case 240: case 241: case 330: case 340: context.aspect_vertical = 2; context.aspect_horizontal = 1; break; case 382: context.aspect_vertical = 1; context.aspect_horizontal = 1; break; default: context.aspect_vertical = 2; context.aspect_horizontal = 1; break; } context.declared_width = 0; context.declared_height = 0; context.row = 0; context.col = 0; /* default isn't white on the VT240, but not sure what it is */ context.current_register = 3; /* FIXME: using green, but not sure what it should be */ if (xw->keyboard.flags & MODE_DECSDM) { TRACE(("sixel scrolling enabled: inline positioning for graphic at %d,%d\n", screen->cur_row, screen->cur_col)); graphic = get_new_graphic(xw, screen->cur_row, screen->cur_col, 0U); } else { TRACE(("sixel scrolling disabled: inline positioning for graphic at %d,%d\n", 0, 0)); graphic = get_new_graphic(xw, 0, 0, 0U); } { int Pmacro = params->a_param[0]; int Pbgmode = params->a_param[1]; int Phgrid = params->a_param[2]; int Pan = params->a_param[3]; int Pad = params->a_param[4]; int Ph = params->a_param[5]; int Pv = params->a_param[6]; (void) Phgrid; TRACE(("sixel bitmap graphics sequence: params=%d (Pmacro=%d Pbgmode=%d Phgrid=%d) scroll_amt=%d\n", params->a_nparam, Pmacro, Pbgmode, Phgrid, screen->scroll_amt)); switch (params->a_nparam) { case 7: if (Pan == 0 || Pad == 0) { TRACE(("DATA_ERROR: invalid raster ratio %d/%d\n", Pan, Pad)); return; } context.aspect_vertical = Pan; context.aspect_horizontal = Pad; if (Ph == 0 || Pv == 0) { TRACE(("DATA_ERROR: raster image dimensions are invalid %dx%d\n", Ph, Pv)); return; } if (Ph > graphic->max_width || Pv > graphic->max_height) { TRACE(("DATA_ERROR: raster image dimensions are too large %dx%d\n", Ph, Pv)); return; } context.declared_width = Ph; context.declared_height = Pv; if (context.declared_width > graphic->actual_width) { graphic->actual_width = context.declared_width; } if (context.declared_height > graphic->actual_height) { graphic->actual_height = context.declared_height; } break; case 3: case 2: case 1: switch (Pmacro) { case 0: /* keep default aspect settings */ break; case 1: case 5: case 6: context.aspect_vertical = 2; context.aspect_horizontal = 1; break; case 2: context.aspect_vertical = 5; context.aspect_horizontal = 1; break; case 3: case 4: context.aspect_vertical = 3; context.aspect_horizontal = 1; break; case 7: case 8: case 9: context.aspect_vertical = 1; context.aspect_horizontal = 1; break; default: TRACE(("DATA_ERROR: unknown sixel macro mode parameter\n")); return; } break; case 0: break; default: TRACE(("DATA_ERROR: unexpected parameter count (found %d)\n", params->a_nparam)); return; } if (Pbgmode == 1) { context.background = COLOR_HOLE; } else { /* FIXME: is the default background register always zero? what about in light background mode? */ context.background = 0; } /* Ignore the grid parameter because it seems only printers paid attention to it. * The VT3xx was always 0.0195 cm. */ } update_sixel_aspect(&context, graphic); for (;;) { ch = CharOf(*string); if (ch == '\0') break; if (ch >= 0x3f && ch <= 0x7e) { int sixel = ch - 0x3f; TRACE(("sixel=%x (%c)\n", sixel, (char) ch)); if (!graphic->valid) { init_sixel_background(graphic, &context); graphic->valid = 1; } set_sixel(graphic, &context, sixel); context.col++; } else if (ch == '$') { /* DECGCR */ /* ignore DECCRNLM in sixel mode */ TRACE(("sixel CR\n")); context.col = 0; } else if (ch == '-') { /* DECGNL */ int scroll_lines; TRACE(("sixel NL\n")); scroll_lines = 0; while (graphic->charrow - scroll_lines + (((context.row + 6) * graphic->pixh + FontHeight(screen) - 1) / FontHeight(screen)) > screen->bot_marg) { scroll_lines++; } context.col = 0; context.row += 6; /* If we hit the bottom margin on the graphics page (well, we just use the * text margin for now), the behavior is to either scroll or to discard * the remainder of the graphic depending on this setting. */ if (scroll_lines > 0) { if (xw->keyboard.flags & MODE_DECSDM) { Display *display = screen->display; xtermScroll(xw, scroll_lines); XSync(display, False); TRACE(("graphic scrolled the screen %d lines. screen->scroll_amt=%d screen->topline=%d, now starting row is %d\n", scroll_lines, screen->scroll_amt, screen->topline, graphic->charrow)); } else { break; } } } else if (ch == '!') { /* DECGRI */ int Pcount; const char *start; int sixel; int i; start = ++string; for (;;) { ch = CharOf(*string); if (ch != '0' && ch != '1' && ch != '2' && ch != '3' && ch != '4' && ch != '5' && ch != '6' && ch != '7' && ch != '8' && ch != '9' && ch != ' ' && ch != '\r' && ch != '\n') break; string++; } if (ch == '\0') { TRACE(("DATA_ERROR: sixel data string terminated in the middle of a repeat operator\n")); return; } if (string == start) { TRACE(("DATA_ERROR: sixel data string contains a repeat operator with empty count\n")); return; } Pcount = atoi(start); sixel = ch - 0x3f; TRACE(("sixel repeat operator: sixel=%d (%c), count=%d\n", sixel, (char) ch, Pcount)); if (!graphic->valid) { init_sixel_background(graphic, &context); graphic->valid = 1; } for (i = 0; i < Pcount; i++) { set_sixel(graphic, &context, sixel); context.col++; } } else if (ch == '#') { /* DECGCI */ ANSI color_params; int Pregister; parse_prefixedtype_params(&color_params, &string); Pregister = color_params.a_param[0]; if (Pregister >= (int) graphic->valid_registers) { TRACE(("DATA_WARNING: sixel color operator uses out-of-range register %d\n", Pregister)); /* FIXME: supposedly the DEC terminals wrapped register indicies -- verify */ while (Pregister >= (int) graphic->valid_registers) Pregister -= (int) graphic->valid_registers; TRACE(("DATA_WARNING: converted to %d\n", Pregister)); } if (color_params.a_nparam > 2 && color_params.a_nparam <= 5) { int Pspace = color_params.a_param[1]; int Pc1 = color_params.a_param[2]; int Pc2 = color_params.a_param[3]; int Pc3 = color_params.a_param[4]; short r, g, b; TRACE(("sixel set color register=%d space=%d color=[%d,%d,%d] (nparams=%d)\n", Pregister, Pspace, Pc1, Pc2, Pc3, color_params.a_nparam)); switch (Pspace) { case 1: /* HLS */ if (Pc1 > 360 || Pc2 > 100 || Pc3 > 100) { TRACE(("DATA_ERROR: sixel set color operator uses out-of-range HLS color coordinates %d,%d,%d\n", Pc1, Pc2, Pc3)); return; } hls2rgb(Pc1, Pc2, Pc3, &r, &g, &b); break; case 2: /* RGB */ if (Pc1 > 100 || Pc2 > 100 || Pc3 > 100) { TRACE(("DATA_ERROR: sixel set color operator uses out-of-range RGB color coordinates %d,%d,%d\n", Pc1, Pc2, Pc3)); return; } r = (short) Pc1; g = (short) Pc2; b = (short) Pc3; break; default: /* unknown */ TRACE(("DATA_ERROR: sixel set color operator uses unknown color space %d\n", Pspace)); return; } update_color_register(graphic, (RegisterNum) Pregister, r, g, b); } else if (color_params.a_nparam == 1) { TRACE(("sixel switch to color register=%d (nparams=%d)\n", Pregister, color_params.a_nparam)); context.current_register = (RegisterNum) Pregister; } else { TRACE(("DATA_ERROR: sixel switch color operator with unexpected parameter count (nparams=%d)\n", color_params.a_nparam)); return; } continue; } else if (ch == '"') /* DECGRA */ { ANSI raster_params; parse_prefixedtype_params(&raster_params, &string); if (raster_params.a_nparam < 2) { TRACE(("DATA_ERROR: sixel raster attribute operator with incomplete parameters (found %d, expected 2 or 4)\n", raster_params.a_nparam)); return; } { int Pan = raster_params.a_param[0]; int Pad = raster_params.a_param[1]; TRACE(("sixel raster attribute with h:w=%d:%d\n", Pan, Pad)); if (Pan == 0 || Pad == 0) { TRACE(("DATA_ERROR: invalid raster ratio %d/%d\n", Pan, Pad)); return; } context.aspect_vertical = Pan; context.aspect_horizontal = Pad; update_sixel_aspect(&context, graphic); } if (raster_params.a_nparam >= 4) { int Ph = raster_params.a_param[2]; int Pv = raster_params.a_param[3]; TRACE(("sixel raster attribute with h=%d v=%d\n", Ph, Pv)); if (Ph == 0 || Pv == 0) { TRACE(("DATA_ERROR: raster image dimensions are invalid %dx%d\n", Ph, Pv)); return; } if (Ph > graphic->max_width || Pv > graphic->max_height) { TRACE(("DATA_ERROR: raster image dimensions are too large %dx%d\n", Ph, Pv)); return; } context.declared_width = Ph; context.declared_height = Pv; if (context.declared_width > graphic->actual_width) { graphic->actual_width = context.declared_width; } if (context.declared_height > graphic->actual_height) { graphic->actual_height = context.declared_height; } } continue; } else if (ch == ' ' || ch == '\r' || ch == '\n') { /* EMPTY */ ; } else { TRACE(("DATA_ERROR: unknown sixel command %04x (%c)\n", (int) ch, ch)); } string++; } /* update the screen */ if (screen->scroll_amt) FlushScroll(xw); if (xw->keyboard.flags & MODE_DECSDM) { int new_row, new_col; if (screen->sixel_scrolls_right) { new_row = (graphic->charrow + (((graphic->actual_height * graphic->pixh) + FontHeight(screen) - 1) / FontHeight(screen)) - 1); new_col = (graphic->charcol + (((graphic->actual_width * graphic->pixw) + FontWidth(screen) - 1) / FontWidth(screen))); } else { /* FIXME: At least of the VT382 the vertical position appears to be * truncated (rounded toward zero after converting to character row. * This code rounds up, which seems more useful, but it would be * better to be compatible. Verify this is true on a VT3[34]0 as * well. */ new_row = (graphic->charrow + (((graphic->actual_height * graphic->pixh) + FontHeight(screen) - 1) / FontHeight(screen))); new_col = 0; } TRACE(("setting text position after %dx%d graphic starting on row=%d col=%d: cursor new_row=%d new_col=%d\n", graphic->actual_width * graphic->pixw, graphic->actual_height * graphic->pixh, graphic->charrow, graphic->charcol, new_row, new_col)); if (new_col > screen->rgt_marg) { new_col = screen->lft_marg; new_row++; TRACE(("column past left margin, overriding to row=%d col=%d\n", new_row, new_col)); } while (new_row > screen->bot_marg) { xtermScroll(xw, 1); new_row--; TRACE(("bottom row was past screen. new start row=%d, cursor row=%d\n", graphic->charrow, new_row)); } if (new_row < 0) { TRACE(("new row is going to be negative (%d)!", new_row)); /* FIXME: this was triggering, now it isn't */ goto finis; } set_cur_row(screen, new_row); set_cur_col(screen, new_col <= screen->rgt_marg ? new_col : screen->rgt_marg); } finis: refresh_modified_displayed_graphics(screen); TRACE(("DONE successfully parsed sixel data\n")); dump_graphic(graphic); }
/* * Clear the given row, for the given range of columns, returning 1 if no * protected characters were found, 0 otherwise. */ static int ClearInLine(register TScreen *screen, int row, int col, int len) { int rc = 1; int flags = TERM_COLOR_FLAGS; /* * If we're clearing to the end of the line, we won't count this as * "drawn" characters. We'll only do cut/paste on "drawn" characters, * so this has the effect of suppressing trailing blanks from a * selection. */ if (col + len + 1 < screen->max_col) flags |= CHARDRAWN; /* If we've marked protected text on the screen, we'll have to * check each time we do an erase. */ if (screen->protected_mode != OFF_PROTECT) { register int n; Char *attrs = SCRN_BUF_ATTRS(screen, row) + col; int saved_mode = screen->protected_mode; Bool done; /* disable this branch during recursion */ screen->protected_mode = OFF_PROTECT; do { done = True; for (n = 0; n < len; n++) { if (attrs[n] & PROTECTED) { rc = 0; /* found a protected segment */ if (n != 0) ClearInLine(screen, row, col, n); while ((n < len) && (attrs[n] & PROTECTED)) n++; done = False; break; } } /* setup for another segment, past the protected text */ if (!done) { attrs += n; col += n; len -= n; } } while (!done); screen->protected_mode = saved_mode; if (len <= 0) return 0; } /* fall through to the final non-protected segment */ if(screen->cursor_state) HideCursor(); screen->do_wrap = 0; if (row - screen->topline <= screen->max_row) { if(!AddToRefresh(screen)) { if(screen->scroll_amt) FlushScroll(screen); ClearCurBackground ( screen, CursorY (screen, row), CurCursorX (screen, row, col), FontHeight(screen), len * CurFontWidth(screen,row)); } } memset(SCRN_BUF_CHARS(screen, row) + col, ' ', len); memset(SCRN_BUF_ATTRS(screen, row) + col, flags, len); if_OPT_ISO_COLORS(screen,{ memset(SCRN_BUF_COLOR(screen, row) + col, xtermColorPair(), len); })
/* * If cursor not in scrolling region, returns. Else, deletes n lines * at the cursor's position, lines added at bottom margin are blank. */ void DeleteLine(register TScreen *screen, register int n) { register int i; register int shift; register int bot; register int refreshtop; register int refreshheight; register int scrolltop; register int scrollheight; if (screen->cur_row < screen->top_marg || screen->cur_row > screen->bot_marg) return; if(screen->cursor_state) HideCursor(); screen->do_wrap = 0; if (n > (i = screen->bot_marg - screen->cur_row + 1)) n = i; if(screen->jumpscroll) { if(screen->scroll_amt >= 0 && screen->cur_row == screen->top_marg) { if(screen->refresh_amt + n > screen->max_row + 1) FlushScroll(screen); screen->scroll_amt += n; screen->refresh_amt += n; } else if(screen->scroll_amt) FlushScroll(screen); } if(!screen->scroll_amt) { shift = -screen->topline; bot = screen->max_row - shift; scrollheight = i - n; refreshheight = n; if((refreshtop = screen->bot_marg - refreshheight + 1 + shift) > (i = screen->max_row - refreshheight + 1)) refreshtop = i; if(screen->scrollWidget && !screen->alternate && screen->cur_row == 0) { scrolltop = 0; if((scrollheight += shift) > i) scrollheight = i; if((i = screen->savedlines) < screen->savelines) { if((i += n) > screen->savelines) i = screen->savelines; screen->savedlines = i; ScrollBarDrawThumb(screen->scrollWidget); } } else { scrolltop = screen->cur_row + shift; if((i = screen->bot_marg - bot) > 0) { scrollheight -= i; if((i = screen->cur_row + n - 1 - bot) >= 0) { refreshheight -= i; } } } vertical_copy_area(screen, scrolltop+n, scrollheight, n); if(refreshheight > 0) { ClearCurBackground(screen, (int) refreshtop * FontHeight(screen) + screen->border, (int) OriginX(screen), (unsigned) refreshheight * FontHeight(screen), (unsigned) Width(screen)); } } /* adjust screen->buf */ if(screen->scrollWidget && !screen->alternate && screen->cur_row == 0) ScrnDeleteLine(screen, screen->allbuf, screen->bot_marg + screen->savelines, 0, n, screen->max_col + 1); else ScrnDeleteLine(screen, screen->visbuf, screen->bot_marg, screen->cur_row, n, screen->max_col + 1); }
/* * scrolls the screen by amount lines, erases bottom, doesn't alter * cursor position (i.e. cursor moves down amount relative to text). * All done within the scrolling region, of course. * requires: amount > 0 */ void Scroll(register TScreen *screen, register int amount) { register int i = screen->bot_marg - screen->top_marg + 1; register int shift; register int bot; register int refreshtop = 0; register int refreshheight; register int scrolltop; register int scrollheight; if(screen->cursor_state) HideCursor(); if (amount > i) amount = i; if(screen->jumpscroll) { if(screen->scroll_amt > 0) { if(screen->refresh_amt + amount > i) FlushScroll(screen); screen->scroll_amt += amount; screen->refresh_amt += amount; } else { if(screen->scroll_amt < 0) FlushScroll(screen); screen->scroll_amt = amount; screen->refresh_amt = amount; } refreshheight = 0; } else { ScrollSelection(screen, -(amount)); if (amount == i) { ClearScreen(screen); return; } shift = -screen->topline; bot = screen->max_row - shift; scrollheight = i - amount; refreshheight = amount; if((refreshtop = screen->bot_marg - refreshheight + 1 + shift) > (i = screen->max_row - refreshheight + 1)) refreshtop = i; if(screen->scrollWidget && !screen->alternate && screen->top_marg == 0) { scrolltop = 0; if((scrollheight += shift) > i) scrollheight = i; if((i = screen->savedlines) < screen->savelines) { if((i += amount) > screen->savelines) i = screen->savelines; screen->savedlines = i; ScrollBarDrawThumb(screen->scrollWidget); } } else { scrolltop = screen->top_marg + shift; if((i = screen->bot_marg - bot) > 0) { scrollheight -= i; if((i = screen->top_marg + amount - 1 - bot) >= 0) { refreshtop += i; refreshheight -= i; } } } if (screen->multiscroll && amount == 1 && screen->topline == 0 && screen->top_marg == 0 && screen->bot_marg == screen->max_row) { if (screen->incopy < 0 && screen->scrolls == 0) CopyWait(screen); screen->scrolls++; } scrolling_copy_area(screen, scrolltop+amount, scrollheight, amount); if(refreshheight > 0) { ClearCurBackground(screen, (int) refreshtop * FontHeight(screen) + screen->border, (int) OriginX(screen), (unsigned) refreshheight * FontHeight(screen), (unsigned) Width(screen)); if(refreshheight > shift) refreshheight = shift; } } if(screen->scrollWidget && !screen->alternate && screen->top_marg == 0) ScrnDeleteLine(screen, screen->allbuf, screen->bot_marg + screen->savelines, 0, amount, screen->max_col + 1); else ScrnDeleteLine(screen, screen->visbuf, screen->bot_marg, screen->top_marg, amount, screen->max_col + 1); if(refreshheight > 0) ScrnRefresh(screen, refreshtop, 0, refreshheight, screen->max_col + 1, False); }