96 lines
2.6 KiB
C
96 lines
2.6 KiB
C
// Virtual software based cursor support
|
|
//
|
|
// Copyright (C) 2014-2016 Kevin O'Connor <kevin@koconnor.net>
|
|
//
|
|
// This file may be distributed under the terms of the GNU LGPLv3 license.
|
|
|
|
#include "biosvar.h" // GET_BDA
|
|
#include "bregs.h" // struct bregs
|
|
#include "vgabios.h" // get_cursor_pos
|
|
#include "vgafb.h" // handle_gfx_op
|
|
#include "vgautil.h" // swcursor_check_event
|
|
|
|
// Draw/undraw a cursor on the framebuffer by xor'ing the cursor cell
|
|
static void
|
|
gfx_set_swcursor(struct vgamode_s *vmode_g, int enable, struct cursorpos cp)
|
|
{
|
|
u16 cursor_type = get_cursor_shape();
|
|
u8 start = cursor_type >> 8, end = cursor_type & 0xff;
|
|
struct gfx_op op;
|
|
init_gfx_op(&op, vmode_g);
|
|
op.x = cp.x * 8;
|
|
int cheight = GET_BDA(char_height);
|
|
op.y = cp.y * cheight + start;
|
|
|
|
int i;
|
|
for (i = start; i < cheight && i <= end; i++, op.y++) {
|
|
op.op = GO_READ8;
|
|
handle_gfx_op(&op);
|
|
int j;
|
|
for (j = 0; j < 8; j++)
|
|
op.pixels[j] ^= 0x07;
|
|
op.op = GO_WRITE8;
|
|
handle_gfx_op(&op);
|
|
}
|
|
}
|
|
|
|
// Draw/undraw a cursor on the screen
|
|
static void
|
|
set_swcursor(int enable)
|
|
{
|
|
u8 flags = GET_BDA_EXT(flags);
|
|
if (!!(flags & BF_SWCURSOR) == enable)
|
|
// Already in requested mode.
|
|
return;
|
|
struct vgamode_s *vmode_g = get_current_mode();
|
|
if (!vmode_g)
|
|
return;
|
|
struct cursorpos cp = get_cursor_pos(GET_BDA(video_page));
|
|
if (cp.x >= GET_BDA(video_cols) || cp.y > GET_BDA(video_rows)
|
|
|| GET_BDA(cursor_type) >= 0x2000)
|
|
// Cursor not visible
|
|
return;
|
|
|
|
SET_BDA_EXT(flags, (flags & ~BF_SWCURSOR) | (enable ? BF_SWCURSOR : 0));
|
|
|
|
if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
|
|
gfx_set_swcursor(vmode_g, enable, cp);
|
|
return;
|
|
}
|
|
|
|
// In text mode, swap foreground and background attributes for cursor
|
|
void *dest_far = text_address(cp) + 1;
|
|
u8 attr = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)dest_far);
|
|
attr = (attr >> 4) | (attr << 4);
|
|
SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)dest_far, attr);
|
|
}
|
|
|
|
// Disable virtual cursor if a vgabios call accesses the framebuffer
|
|
void
|
|
swcursor_pre_handle10(struct bregs *regs)
|
|
{
|
|
if (!vga_emulate_text())
|
|
return;
|
|
switch (regs->ah) {
|
|
case 0x4f:
|
|
if (!CONFIG_VGA_VBE || regs->al != 0x02)
|
|
break;
|
|
// NO BREAK
|
|
case 0x00 ... 0x02:
|
|
case 0x05 ... 0x0e:
|
|
case 0x13:
|
|
set_swcursor(0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Called by periodic (18.2hz) timer
|
|
void
|
|
swcursor_check_event(void)
|
|
{
|
|
if (!vga_emulate_text())
|
|
return;
|
|
set_swcursor(GET_BDA(timer_counter) % 18 < 9);
|
|
}
|