1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-22 15:47:37 +00:00

vt(4): Fix cursor handling in vt_flush()

There were situations where the cursor was not erased/redrawn or its
position was marked as dirty even though it's not displayed. The code is
now more straightforward.

At the same, add a function to determine if the cursor covers a given
area. This is used by backends to know if they need to draw the cursor.

This new function should be paired with a new state in struct vt_device,
called vd_mshown, which indicates if the cursor should be displayed.
This again simplifies vd_bitblt_text_t callback's API.

MFC after:	1 week
This commit is contained in:
Jean-Sébastien Pédron 2014-08-23 11:46:52 +00:00
parent f81018caf2
commit 946d0288f2
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=270404
3 changed files with 100 additions and 58 deletions

View File

@ -521,8 +521,7 @@ vga_bitblt_pixels_block_ncolors(struct vt_device *vd, const uint8_t *masks,
static void
vga_bitblt_one_text_pixels_block(struct vt_device *vd,
const struct vt_window *vw, unsigned int x, unsigned int y,
int cursor_displayed)
const struct vt_window *vw, unsigned int x, unsigned int y)
{
const struct vt_buf *vb;
const struct vt_font *vf;
@ -533,10 +532,6 @@ vga_bitblt_one_text_pixels_block(struct vt_device *vd,
term_char_t c;
term_color_t fg, bg;
const uint8_t *src;
#ifndef SC_NO_CUTPASTE
struct vt_mouse_cursor *cursor;
unsigned int mx, my;
#endif
vb = &vw->vw_buf;
vf = vw->vw_font;
@ -631,16 +626,21 @@ vga_bitblt_one_text_pixels_block(struct vt_device *vd,
* the current position could be different than the one used
* to mark the area dirty.
*/
cursor = vd->vd_mcursor;
mx = vd->vd_moldx + vw->vw_offset.tp_col;
my = vd->vd_moldy + vw->vw_offset.tp_row;
if (cursor_displayed &&
((mx >= x && x + VT_VGA_PIXELS_BLOCK - 1 >= mx) ||
(mx < x && mx + cursor->width >= x)) &&
((my >= y && y + vf->vf_height - 1 >= my) ||
(my < y && my + cursor->height >= y))) {
term_rect_t drawn_area;
drawn_area.tr_begin.tp_col = x;
drawn_area.tr_begin.tp_row = y;
drawn_area.tr_end.tp_col = x + VT_VGA_PIXELS_BLOCK;
drawn_area.tr_end.tp_row = y + vf->vf_height;
if (vd->vd_mshown && vt_is_cursor_in_area(vd, &drawn_area)) {
struct vt_mouse_cursor *cursor;
unsigned int mx, my;
unsigned int dst_x, src_y, dst_y, y_count;
cursor = vd->vd_mcursor;
mx = vd->vd_mx_drawn + vw->vw_offset.tp_col;
my = vd->vd_my_drawn + vw->vw_offset.tp_row;
/* Compute the portion of the cursor we want to copy. */
src_x = x > mx ? x - mx : 0;
dst_x = mx > x ? mx - x : 0;
@ -686,7 +686,7 @@ vga_bitblt_one_text_pixels_block(struct vt_device *vd,
static void
vga_bitblt_text_gfxmode(struct vt_device *vd, const struct vt_window *vw,
const term_rect_t *area, int cursor_displayed)
const term_rect_t *area)
{
const struct vt_font *vf;
unsigned int col, row;
@ -741,7 +741,11 @@ vga_bitblt_text_gfxmode(struct vt_device *vd, const struct vt_window *vw,
* VT_VGA_PIXELS_BLOCK;
y2 = row * vf->vf_height + vw->vw_offset.tp_row;
/* Clip the area to the screen size. */
/*
* Clip the area to the screen size.
*
* FIXME: Take vw_offset into account.
*/
x2 = min(x2, vd->vd_width - 1);
y2 = min(y2, vd->vd_height - 1);
@ -762,15 +766,14 @@ vga_bitblt_text_gfxmode(struct vt_device *vd, const struct vt_window *vw,
for (y = y1; y < y2; y += vf->vf_height) {
for (x = x1; x < x2; x += VT_VGA_PIXELS_BLOCK) {
vga_bitblt_one_text_pixels_block(vd, vw, x, y,
cursor_displayed);
vga_bitblt_one_text_pixels_block(vd, vw, x, y);
}
}
}
static void
vga_bitblt_text_txtmode(struct vt_device *vd, const struct vt_window *vw,
const term_rect_t *area, int cursor_displayed)
const term_rect_t *area)
{
struct vga_softc *sc;
const struct vt_buf *vb;
@ -814,13 +817,13 @@ vga_bitblt_text_txtmode(struct vt_device *vd, const struct vt_window *vw,
static void
vga_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
const term_rect_t *area, int cursor_displayed)
const term_rect_t *area)
{
if (!(vd->vd_flags & VDF_TEXTMODE)) {
vga_bitblt_text_gfxmode(vd, vw, area, cursor_displayed);
vga_bitblt_text_gfxmode(vd, vw, area);
} else {
vga_bitblt_text_txtmode(vd, vw, area, cursor_displayed);
vga_bitblt_text_txtmode(vd, vw, area);
}
}

View File

@ -130,11 +130,12 @@ struct vt_device {
struct vt_mouse_cursor *vd_mcursor; /* (?) Cursor bitmap. */
term_color_t vd_mcursor_fg; /* (?) Cursor fg color. */
term_color_t vd_mcursor_bg; /* (?) Cursor bg color. */
#endif
vt_axis_t vd_mx_drawn; /* (?) Mouse X and Y */
vt_axis_t vd_my_drawn; /* as of last redraw. */
int vd_mshown; /* (?) Mouse shown during */
#endif /* last redrawn. */
uint16_t vd_mx; /* (?) Current mouse X. */
uint16_t vd_my; /* (?) current mouse Y. */
vt_axis_t vd_moldx; /* (?) Mouse X as of last redraw. */
vt_axis_t vd_moldy; /* (?) Mouse Y as of last redraw. */
uint32_t vd_mstate; /* (?) Mouse state. */
vt_axis_t vd_width; /* (?) Screen width. */
vt_axis_t vd_height; /* (?) Screen height. */
@ -303,7 +304,7 @@ typedef void vd_bitbltchr_t(struct vt_device *vd, const uint8_t *src,
typedef void vd_putchar_t(struct vt_device *vd, term_char_t,
vt_axis_t top, vt_axis_t left, term_color_t fg, term_color_t bg);
typedef void vd_bitblt_text_t(struct vt_device *vd, const struct vt_window *vw,
const term_rect_t *area, int cursor_displayed);
const term_rect_t *area);
typedef int vd_fb_ioctl_t(struct vt_device *, u_long, caddr_t, struct thread *);
typedef int vd_fb_mmap_t(struct vt_device *, vm_ooffset_t, vm_paddr_t *, int,
vm_memattr_t *);
@ -415,6 +416,8 @@ void vt_mouse_state(int show);
/* Utilities. */
void vt_determine_colors(term_char_t c, int cursor,
term_color_t *fg, term_color_t *bg);
int vt_is_cursor_in_area(const struct vt_device *vd,
const term_rect_t *area);
#endif /* !_DEV_VT_VT_H_ */

View File

@ -819,16 +819,46 @@ vt_determine_colors(term_char_t c, int cursor,
}
#ifndef SC_NO_CUTPASTE
int
vt_is_cursor_in_area(const struct vt_device *vd, const term_rect_t *area)
{
unsigned int mx, my, x1, y1, x2, y2;
/*
* We use the cursor position saved during the current refresh,
* in case the cursor moved since.
*/
mx = vd->vd_mx_drawn;
my = vd->vd_my_drawn;
x1 = area->tr_begin.tp_col;
y1 = area->tr_begin.tp_row;
x2 = area->tr_end.tp_col;
y2 = area->tr_end.tp_row;
if (((mx >= x1 && x2 - 1 >= mx) ||
(mx < x1 && mx + vd->vd_mcursor->width >= x1)) &&
((my >= y1 && y2 - 1 >= my) ||
(my < y1 && my + vd->vd_mcursor->height >= y1)))
return (1);
return (0);
}
static void
vt_mark_mouse_position_as_dirty(struct vt_device *vd, int x, int y)
vt_mark_mouse_position_as_dirty(struct vt_device *vd)
{
term_rect_t area;
struct vt_window *vw;
struct vt_font *vf;
int x, y;
vw = vd->vd_curwindow;
vf = vw->vw_font;
x = vd->vd_mx_drawn;
y = vd->vd_my_drawn;
if (vf != NULL) {
area.tr_begin.tp_col = (x - vw->vw_offset.tp_col) /
vf->vf_width;
@ -897,9 +927,8 @@ vt_flush(struct vt_device *vd)
term_rect_t tarea;
term_pos_t size;
term_char_t *r;
int cursor_displayed;
#ifndef SC_NO_CUTPASTE
int bpl, h, w;
int cursor_was_shown, cursor_moved, bpl, h, w;
#endif
vw = vd->vd_curwindow;
@ -913,34 +942,42 @@ vt_flush(struct vt_device *vd)
if (((vd->vd_flags & VDF_TEXTMODE) == 0) && (vf == NULL))
return;
cursor_displayed = 0;
#ifndef SC_NO_CUTPASTE
cursor_was_shown = vd->vd_mshown;
cursor_moved = (vd->vd_mx != vd->vd_mx_drawn ||
vd->vd_my != vd->vd_my_drawn);
/* Check if the cursor should be displayed or not. */
if ((vd->vd_flags & VDF_MOUSECURSOR) && /* Mouse support enabled. */
!(vw->vw_flags & VWF_MOUSE_HIDE)) { /* Cursor displayed. */
if (vd->vd_moldx != vd->vd_mx ||
vd->vd_moldy != vd->vd_my) {
/* Mark last mouse position as dirty to erase. */
vt_mark_mouse_position_as_dirty(vd,
vd->vd_moldx, vd->vd_moldy);
/*
* Save point of last mouse cursor to erase it
* later.
*/
vd->vd_moldx = vd->vd_mx;
vd->vd_moldy = vd->vd_my;
}
if (!kdb_active && panicstr == NULL) {
/* Mouse enabled, and DDB isn't active. */
cursor_displayed = 1;
/* Mark new mouse position as dirty. */
vt_mark_mouse_position_as_dirty(vd,
vd->vd_mx, vd->vd_my);
}
!(vw->vw_flags & VWF_MOUSE_HIDE) && /* Cursor displayed. */
!kdb_active && panicstr == NULL) { /* DDB inactive. */
vd->vd_mshown = 1;
} else {
vd->vd_mshown = 0;
}
/*
* If the cursor changed display state or moved, we must mark
* the old position as dirty, so that it's erased.
*/
if (cursor_was_shown != vd->vd_mshown ||
(vd->vd_mshown && cursor_moved))
vt_mark_mouse_position_as_dirty(vd);
/*
* Save position of the mouse cursor. It's used by backends to
* know where to draw the cursor and during the next refresh to
* erase the previous position.
*/
vd->vd_mx_drawn = vd->vd_mx;
vd->vd_my_drawn = vd->vd_my;
/*
* If the cursor is displayed and has moved since last refresh,
* mark the new position as dirty.
*/
if (vd->vd_mshown && cursor_moved)
vt_mark_mouse_position_as_dirty(vd);
#endif
vtbuf_undirty(&vw->vw_buf, &tarea, &tmask);
@ -957,8 +994,7 @@ vt_flush(struct vt_device *vd)
if (vd->vd_driver->vd_bitblt_text != NULL) {
if (tarea.tr_begin.tp_col < tarea.tr_end.tp_col) {
vd->vd_driver->vd_bitblt_text(vd, vw, &tarea,
cursor_displayed);
vd->vd_driver->vd_bitblt_text(vd, vw, &tarea);
}
} else {
/*
@ -980,7 +1016,7 @@ vt_flush(struct vt_device *vd)
}
#ifndef SC_NO_CUTPASTE
if (cursor_displayed) {
if (vd->vd_mshown) {
/* Bytes per source line. */
bpl = (vd->vd_mcursor->width + 7) >> 3;
w = vd->vd_mcursor->width;
@ -1640,7 +1676,7 @@ vt_mouse_state(int show)
}
/* Mark mouse position as dirty. */
vt_mark_mouse_position_as_dirty(vd, vd->vd_mx, vd->vd_my);
vt_mark_mouse_position_as_dirty(vd);
}
#endif