From owner-svn-src-all@FreeBSD.ORG Sat Aug 23 11:46:53 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 95B29F21; Sat, 23 Aug 2014 11:46:53 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 769653BF7; Sat, 23 Aug 2014 11:46:53 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s7NBkrp5066751; Sat, 23 Aug 2014 11:46:53 GMT (envelope-from dumbbell@FreeBSD.org) Received: (from dumbbell@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s7NBkq2f066747; Sat, 23 Aug 2014 11:46:52 GMT (envelope-from dumbbell@FreeBSD.org) Message-Id: <201408231146.s7NBkq2f066747@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: dumbbell set sender to dumbbell@FreeBSD.org using -f From: Jean-Sebastien Pedron Date: Sat, 23 Aug 2014 11:46:52 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r270404 - in head/sys/dev/vt: . hw/vga X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 23 Aug 2014 11:46:53 -0000 Author: dumbbell Date: Sat Aug 23 11:46:52 2014 New Revision: 270404 URL: http://svnweb.freebsd.org/changeset/base/270404 Log: 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 Modified: head/sys/dev/vt/hw/vga/vt_vga.c head/sys/dev/vt/vt.h head/sys/dev/vt/vt_core.c Modified: head/sys/dev/vt/hw/vga/vt_vga.c ============================================================================== --- head/sys/dev/vt/hw/vga/vt_vga.c Sat Aug 23 11:46:26 2014 (r270403) +++ head/sys/dev/vt/hw/vga/vt_vga.c Sat Aug 23 11:46:52 2014 (r270404) @@ -521,8 +521,7 @@ vga_bitblt_pixels_block_ncolors(struct v 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 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 * 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 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 * 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 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 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); } } Modified: head/sys/dev/vt/vt.h ============================================================================== --- head/sys/dev/vt/vt.h Sat Aug 23 11:46:26 2014 (r270403) +++ head/sys/dev/vt/vt.h Sat Aug 23 11:46:52 2014 (r270404) @@ -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_de 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_ */ Modified: head/sys/dev/vt/vt_core.c ============================================================================== --- head/sys/dev/vt/vt_core.c Sat Aug 23 11:46:26 2014 (r270403) +++ head/sys/dev/vt/vt_core.c Sat Aug 23 11:46:52 2014 (r270404) @@ -819,16 +819,46 @@ vt_determine_colors(term_char_t c, int c } #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); + !(vw->vw_flags & VWF_MOUSE_HIDE) && /* Cursor displayed. */ + !kdb_active && panicstr == NULL) { /* DDB inactive. */ + vd->vd_mshown = 1; + } else { + vd->vd_mshown = 0; + } - /* - * Save point of last mouse cursor to erase it - * later. - */ - vd->vd_moldx = vd->vd_mx; - vd->vd_moldy = vd->vd_my; - } + /* + * 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); - if (!kdb_active && panicstr == NULL) { - /* Mouse enabled, and DDB isn't active. */ - cursor_displayed = 1; + /* + * 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; - /* Mark new mouse position as dirty. */ - vt_mark_mouse_position_as_dirty(vd, - vd->vd_mx, 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