if (pcp->y > nbrows) {
pcp->y--;
- struct cursorpos dest = {0, 0, pcp->page};
- struct cursorpos src = {0, 1, pcp->page};
- struct cursorpos size = {GET_BDA(video_cols), nbrows};
- vgafb_move_chars(dest, src, size);
-
- struct cursorpos clr = {0, nbrows, pcp->page};
+ struct cursorpos win = {0, 0, pcp->page};
+ struct cursorpos winsize = {GET_BDA(video_cols), nbrows+1};
struct carattr attr = {' ', 0, 0};
- struct cursorpos clrsize = {GET_BDA(video_cols), 1};
- vgafb_clear_chars(clr, attr, clrsize);
+ vgafb_scroll(win, winsize, 1, attr);
}
}
static void
verify_scroll(struct bregs *regs, int dir)
{
+ // Verify parameters
u8 ulx = regs->cl, uly = regs->ch, lrx = regs->dl, lry = regs->dh;
u16 nbrows = GET_BDA(video_rows) + 1;
if (lry >= nbrows)
int wincols = lrx - ulx + 1, winrows = lry - uly + 1;
if (wincols <= 0 || winrows <= 0)
return;
-
- u8 page = GET_BDA(video_page);
- int clearlines = regs->al, movelines = winrows - clearlines;
- if (!clearlines || movelines <= 0) {
- // Clear whole area.
- struct cursorpos clr = {ulx, uly, page};
- struct carattr attr = {' ', regs->bh, 1};
- struct cursorpos clrsize = {wincols, winrows};
- vgafb_clear_chars(clr, attr, clrsize);
- return;
- }
-
- if (dir > 0) {
- // Normal scroll
- struct cursorpos dest = {ulx, uly, page};
- struct cursorpos src = {ulx, uly + clearlines, page};
- struct cursorpos size = {wincols, movelines};
- vgafb_move_chars(dest, src, size);
-
- struct cursorpos clr = {ulx, uly + movelines, page};
- struct carattr attr = {' ', regs->bh, 1};
- struct cursorpos clrsize = {wincols, clearlines};
- vgafb_clear_chars(clr, attr, clrsize);
- } else {
- // Scroll down
- struct cursorpos dest = {ulx, uly + clearlines, page};
- struct cursorpos src = {ulx, uly, page};
- struct cursorpos size = {wincols, movelines};
- vgafb_move_chars(dest, src, size);
-
- struct cursorpos clr = {ulx, uly, page};
- struct carattr attr = {' ', regs->bh, 1};
- struct cursorpos clrsize = {wincols, clearlines};
- vgafb_clear_chars(clr, attr, clrsize);
- }
+ int lines = regs->al;
+ if (lines >= winrows)
+ lines = 0;
+ lines *= dir;
+
+ // Scroll (or clear) window
+ struct cursorpos win = {ulx, uly, GET_BDA(video_page)};
+ struct cursorpos winsize = {wincols, winrows};
+ struct carattr attr = {' ', regs->bh, 1};
+ vgafb_scroll(win, winsize, lines, attr);
}
static void
// Move characters when in graphics mode.
static void
gfx_move_chars(struct vgamode_s *vmode_g, struct cursorpos dest
- , struct cursorpos src, struct cursorpos movesize)
+ , struct cursorpos movesize, int lines)
{
struct gfx_op op;
init_gfx_op(&op, vmode_g);
int cheight = GET_BDA(char_height);
op.y = dest.y * cheight;
op.ylen = movesize.y * cheight;
- op.srcy = src.y * cheight;
+ op.srcy = op.y + lines * cheight;
op.op = GO_MEMMOVE;
handle_gfx_op(&op);
}
// Clear area of screen in graphics mode.
static void
-gfx_clear_chars(struct vgamode_s *vmode_g, struct cursorpos dest
- , struct carattr ca, struct cursorpos clearsize)
+gfx_clear_chars(struct vgamode_s *vmode_g, struct cursorpos win
+ , struct cursorpos winsize, struct carattr ca)
{
struct gfx_op op;
init_gfx_op(&op, vmode_g);
- op.x = dest.x * 8;
- op.xlen = clearsize.x * 8;
+ op.x = win.x * 8;
+ op.xlen = winsize.x * 8;
int cheight = GET_BDA(char_height);
- op.y = dest.y * cheight;
- op.ylen = clearsize.y * cheight;
+ op.y = win.y * cheight;
+ op.ylen = winsize.y * cheight;
op.pixels[0] = ca.attr;
if (vga_emulate_text())
op.pixels[0] = ca.attr >> 4;
}
// Move characters on screen.
-void
-vgafb_move_chars(struct cursorpos dest
- , struct cursorpos src, struct cursorpos movesize)
+static void
+vgafb_move_chars(struct cursorpos dest, struct cursorpos movesize, int lines)
{
struct vgamode_s *vmode_g = get_current_mode();
if (!vmode_g)
return;
- vgafb_set_swcursor(0);
if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
- gfx_move_chars(vmode_g, dest, src, movesize);
+ gfx_move_chars(vmode_g, dest, movesize, lines);
return;
}
int stride = GET_BDA(video_cols) * 2;
- memmove_stride(GET_GLOBAL(vmode_g->sstart)
- , text_address(dest), text_address(src)
+ void *dest_addr = text_address(dest), *src_addr = dest_addr + lines * stride;
+ memmove_stride(GET_GLOBAL(vmode_g->sstart), dest_addr, src_addr
, movesize.x * 2, stride, movesize.y);
}
// Clear area of screen.
-void
-vgafb_clear_chars(struct cursorpos dest
- , struct carattr ca, struct cursorpos clearsize)
+static void
+vgafb_clear_chars(struct cursorpos win, struct cursorpos winsize
+ , struct carattr ca)
{
struct vgamode_s *vmode_g = get_current_mode();
if (!vmode_g)
return;
- vgafb_set_swcursor(0);
if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
- gfx_clear_chars(vmode_g, dest, ca, clearsize);
+ gfx_clear_chars(vmode_g, win, winsize, ca);
return;
}
int stride = GET_BDA(video_cols) * 2;
u16 attr = ((ca.use_attr ? ca.attr : 0x07) << 8) | ca.car;
- memset16_stride(GET_GLOBAL(vmode_g->sstart), text_address(dest), attr
- , clearsize.x * 2, stride, clearsize.y);
+ memset16_stride(GET_GLOBAL(vmode_g->sstart), text_address(win), attr
+ , winsize.x * 2, stride, winsize.y);
+}
+
+// Scroll characters within a window on the screen
+void
+vgafb_scroll(struct cursorpos win, struct cursorpos winsize
+ , int lines, struct carattr ca)
+{
+ vgafb_set_swcursor(0);
+ if (!lines) {
+ // Clear window
+ vgafb_clear_chars(win, winsize, ca);
+ } else if (lines > 0) {
+ // Scroll the window up (eg, from page down key)
+ winsize.y -= lines;
+ vgafb_move_chars(win, winsize, lines);
+
+ win.y += winsize.y;
+ winsize.y = lines;
+ vgafb_clear_chars(win, winsize, ca);
+ } else {
+ // Scroll the window down (eg, from page up key)
+ win.y -= lines;
+ winsize.y += lines;
+ vgafb_move_chars(win, winsize, lines);
+
+ win.y += lines;
+ winsize.y = -lines;
+ vgafb_clear_chars(win, winsize, ca);
+ }
}
// Write a character to the screen.