Author: dumbbell
Date: Fri Sep 19 12:20:43 2014
New Revision: 271871
URL: http://svnweb.freebsd.org/changeset/base/271871

Log:
  vt(4): Rewrite history scrolling
  
  It's now possible to scroll up the 500 hard-coded lines of history, not
  just a fraction of them. For instance, one can reach the top of the boot
  process.
  
  Sometimes, when scrolling or when changing the screen size (by changing
  the font or loading a KMS driver for instance), one could see the
  history cycling (old content appeared below latest lines). This is
  fixed.
  
  Now, when the resolution changes are more lines can be shown, the
  displayed area is adjusted so that, if the screen was filled with
  content before, it's filled with content after as well: more history
  is visible, instead of having blank lines below the previously visible
  content.
  
  MFC after:    3 days

Modified:
  head/sys/dev/vt/vt_buf.c
  head/sys/dev/vt/vt_core.c

Modified: head/sys/dev/vt/vt_buf.c
==============================================================================
--- head/sys/dev/vt/vt_buf.c    Fri Sep 19 11:49:41 2014        (r271870)
+++ head/sys/dev/vt/vt_buf.c    Fri Sep 19 12:20:43 2014        (r271871)
@@ -76,44 +76,46 @@ vthistory_seek(struct vt_buf *vb, int of
                }
                return (0); /* No changes */
        }
-       top = (vb->vb_flags & VBF_HISTORY_FULL)?
-           (vb->vb_curroffset + vb->vb_scr_size.tp_row):vb->vb_history_size;
-       bottom = vb->vb_curroffset + vb->vb_history_size;
 
-       /*
-        * Operate on copy of offset value, since it temporary can be bigger
-        * than amount of rows in buffer.
-        */
-       roffset = vb->vb_roffset + vb->vb_history_size;
+       /* "top" may be a negative integer. */
+       bottom = vb->vb_curroffset;
+       top = (vb->vb_flags & VBF_HISTORY_FULL) ?
+           bottom + vb->vb_scr_size.tp_row - vb->vb_history_size :
+           0;
+
        switch (whence) {
        case VHS_SET:
-               roffset = offset + vb->vb_history_size;
+               if (offset < 0)
+                       offset = 0;
+               roffset = top + offset;
                break;
        case VHS_CUR:
+               /*
+                * Operate on copy of offset value, since it temporary
+                * can be bigger than amount of rows in buffer.
+                */
+               roffset = vb->vb_roffset;
+               if (roffset >= bottom + vb->vb_scr_size.tp_row)
+                       roffset -= vb->vb_history_size;
+
                roffset += offset;
+               roffset = MAX(roffset, top);
+               roffset = MIN(roffset, bottom);
+
+               if (roffset < 0)
+                       roffset = vb->vb_history_size + roffset;
+
                break;
        case VHS_END:
                /* Go to current offset. */
-               roffset = vb->vb_curroffset + vb->vb_history_size;
+               roffset = vb->vb_curroffset;
                break;
        }
 
-       roffset = (roffset < top)?top:roffset;
-       roffset = (roffset > bottom)?bottom:roffset;
-
-       roffset %= vb->vb_history_size;
+       diff = vb->vb_roffset != roffset;
+       vb->vb_roffset = roffset;
 
-       if (vb->vb_roffset != roffset) {
-               diff = vb->vb_roffset - roffset;
-               vb->vb_roffset = roffset;
-               /*
-                * Offset changed, please update Nth lines on sceen.
-                * +N - Nth lines at top;
-                * -N - Nth lines at bottom.
-                */
-               return (diff);
-       }
-       return (0); /* No changes */
+       return (diff);
 }
 
 void
@@ -123,6 +125,8 @@ vthistory_addlines(struct vt_buf *vb, in
        vb->vb_curroffset += offset;
        if (vb->vb_curroffset < 0)
                vb->vb_curroffset = 0;
+       if (vb->vb_curroffset + vb->vb_scr_size.tp_row >= vb->vb_history_size)
+               vb->vb_flags |= VBF_HISTORY_FULL;
        vb->vb_curroffset %= vb->vb_history_size;
        if ((vb->vb_flags & VBF_SCROLL) == 0) {
                vb->vb_roffset = vb->vb_curroffset;
@@ -414,71 +418,155 @@ vtbuf_sethistory_size(struct vt_buf *vb,
 void
 vtbuf_grow(struct vt_buf *vb, const term_pos_t *p, unsigned int history_size)
 {
-       term_char_t *old, *new, **rows, **oldrows, **copyrows, *row;
-       int bufsize, rowssize, w, h, c, r;
+       term_char_t *old, *new, **rows, **oldrows, **copyrows, *row, *oldrow;
+       int bufsize, rowssize, w, h, c, r, history_was_full;
+       unsigned int old_history_size;
        term_rect_t rect;
 
        history_size = MAX(history_size, p->tp_row);
 
-       /* If new screen/history size bigger or buffer is VBF_STATIC. */
-       if ((history_size > vb->vb_history_size) || (p->tp_col >
-           vb->vb_scr_size.tp_col) || (vb->vb_flags & VBF_STATIC)) {
-               /* Allocate new buffer. */
-               bufsize = history_size * p->tp_col * sizeof(term_char_t);
-               new = malloc(bufsize, M_VTBUF, M_WAITOK | M_ZERO);
-               rowssize = history_size * sizeof(term_pos_t *);
-               rows = malloc(rowssize, M_VTBUF, M_WAITOK | M_ZERO);
+       /* Allocate new buffer. */
+       bufsize = history_size * p->tp_col * sizeof(term_char_t);
+       new = malloc(bufsize, M_VTBUF, M_WAITOK | M_ZERO);
+       rowssize = history_size * sizeof(term_pos_t *);
+       rows = malloc(rowssize, M_VTBUF, M_WAITOK | M_ZERO);
 
-               /* Toggle it. */
-               VTBUF_LOCK(vb);
-               old = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_buffer;
-               oldrows = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_rows;
-               copyrows = vb->vb_rows;
-               w = vb->vb_scr_size.tp_col;
-               h = vb->vb_history_size;
-
-               vb->vb_history_size = history_size;
-               vb->vb_buffer = new;
-               vb->vb_rows = rows;
-               vb->vb_flags &= ~VBF_STATIC;
-               vb->vb_scr_size = *p;
-               vtbuf_init_rows(vb);
+       /* Toggle it. */
+       VTBUF_LOCK(vb);
+       old = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_buffer;
+       oldrows = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_rows;
+       copyrows = vb->vb_rows;
+
+       w = vb->vb_scr_size.tp_col;
+       h = vb->vb_scr_size.tp_row;
+       old_history_size = vb->vb_history_size;
+       history_was_full = vb->vb_flags & VBF_HISTORY_FULL;
+
+       vb->vb_history_size = history_size;
+       vb->vb_buffer = new;
+       vb->vb_rows = rows;
+       vb->vb_flags &= ~VBF_STATIC;
+       vb->vb_scr_size = *p;
+       vtbuf_init_rows(vb);
+
+       /* Copy history and fill extra space if needed. */
+       if (history_size > old_history_size) {
+               /*
+                * Copy rows to the new buffer. The first row in the history
+                * is back to index 0, ie. the new buffer doesn't cycle.
+                *
+                * The rest of the new buffer is initialized with blank
+                * content.
+                */
+               for (r = 0; r < old_history_size; r ++) {
+                       row = rows[r];
+
+                       /* Compute the corresponding row in the old buffer. */
+                       if (history_was_full)
+                               /*
+                                * The buffer is full, the "top" row is
+                                * the one just after the viewable area
+                                * (curroffset + viewable height) in the
+                                * cycling buffer. The corresponding row
+                                * is computed from this top row.
+                                */
+                               oldrow = copyrows[
+                                   (vb->vb_curroffset + h + r) %
+                                   old_history_size];
+                       else
+                               /*
+                                * The buffer is not full, therefore,
+                                * we didn't cycle already. The
+                                * corresponding rows are the same in
+                                * both buffers.
+                                */
+                               oldrow = copyrows[r];
+
+                       memmove(row, oldrow,
+                           MIN(p->tp_col, w) * sizeof(term_char_t));
 
-               /* Copy history and fill extra space. */
-               for (r = 0; r < history_size; r ++) {
                        /*
                         * XXX VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR) will
                         * extended lines of kernel text using the wrong
                         * background color.
                         */
-                       row = rows[r];
-                       if (r < h) { /* Copy. */
-                               memmove(rows[r], copyrows[r],
-                                   MIN(p->tp_col, w) * sizeof(term_char_t));
-                               for (c = MIN(p->tp_col, w); c < p->tp_col;
-                                   c++) {
-                                       row[c] = VTBUF_SPACE_CHAR(
-                                           TERMINAL_NORM_ATTR);
-                               }
-                       } else { /* Just fill. */
-                               rect.tr_begin.tp_col = 0;
-                               rect.tr_begin.tp_row = r;
-                               rect.tr_end.tp_col = p->tp_col;
-                               rect.tr_end.tp_row = p->tp_row;
-                               vtbuf_fill(vb, &rect,
-                                   VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR));
-                               break;
+                       for (c = MIN(p->tp_col, w); c < p->tp_col; c++) {
+                               row[c] = VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR);
                        }
                }
-               vtbuf_make_undirty(vb);
-               VTBUF_UNLOCK(vb);
-               /* Deallocate old buffer. */
-               free(old, M_VTBUF);
-               free(oldrows, M_VTBUF);
+
+               /* Fill remaining rows. */
+               rect.tr_begin.tp_col = 0;
+               rect.tr_begin.tp_row = old_history_size;
+               rect.tr_end.tp_col = p->tp_col;
+               rect.tr_end.tp_row = p->tp_row;
+               vtbuf_fill(vb, &rect, VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR));
+
+               vb->vb_flags &= ~VBF_HISTORY_FULL;
        } else {
-               /* Just update the size. */
-               vb->vb_scr_size = *p;
+               /*
+                * Copy rows to the new buffer. The first row in the history
+                * is back to index 0, ie. the new buffer doesn't cycle.
+                *
+                * (old_history_size - history_size) lines of history are
+                * dropped.
+                */
+               for (r = 0; r < history_size; r ++) {
+                       row = rows[r];
+
+                       /*
+                        * Compute the corresponding row in the old buffer.
+                        *
+                        * See the equivalent if{} block above for an
+                        * explanation.
+                        */
+                       if (history_was_full)
+                               oldrow = copyrows[
+                                   (vb->vb_curroffset + h + r +
+                                    (old_history_size - history_size)) %
+                                   old_history_size];
+                       else
+                               oldrow = copyrows[
+                                   (r + (old_history_size - history_size)) %
+                                   old_history_size];
+
+                       memmove(row, oldrow,
+                           MIN(p->tp_col, w) * sizeof(term_char_t));
+
+                       /*
+                        * XXX VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR) will
+                        * extended lines of kernel text using the wrong
+                        * background color.
+                        */
+                       for (c = MIN(p->tp_col, w); c < p->tp_col; c++) {
+                               row[c] = VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR);
+                       }
+               }
+
+               if (!history_was_full &&
+                   (vb->vb_curroffset + h) >= history_size)
+                       vb->vb_flags |= VBF_HISTORY_FULL;
        }
+
+       /*
+        * If the screen is already filled (there are non-visible lines
+        * above the current viewable area), adjust curroffset to the
+        * new viewable area.
+        */
+       if (!history_was_full && vb->vb_curroffset > 0) {
+               vb->vb_curroffset = vb->vb_curroffset + h - p->tp_row;
+               if (vb->vb_curroffset < 0)
+                       vb->vb_curroffset += vb->vb_history_size;
+               vb->vb_curroffset %= vb->vb_history_size;
+               vb->vb_roffset = vb->vb_curroffset;
+       }
+
+       vtbuf_make_undirty(vb);
+       VTBUF_UNLOCK(vb);
+
+       /* Deallocate old buffer. */
+       free(old, M_VTBUF);
+       free(oldrows, M_VTBUF);
 }
 
 void

Modified: head/sys/dev/vt/vt_core.c
==============================================================================
--- head/sys/dev/vt/vt_core.c   Fri Sep 19 11:49:41 2014        (r271870)
+++ head/sys/dev/vt/vt_core.c   Fri Sep 19 12:20:43 2014        (r271871)
@@ -484,18 +484,8 @@ vt_scroll(struct vt_window *vw, int offs
        vt_termsize(vw->vw_device, vw->vw_font, &size);
 
        diff = vthistory_seek(&vw->vw_buf, offset, whence);
-       /*
-        * Offset changed, please update Nth lines on screen.
-        * +N - Nth lines at top;
-        * -N - Nth lines at bottom.
-        */
-
-       if (diff < -size.tp_row || diff > size.tp_row) {
+       if (diff)
                vw->vw_device->vd_flags |= VDF_INVALID;
-               vt_resume_flush_timer(vw->vw_device, 0);
-               return;
-       }
-       vw->vw_device->vd_flags |= VDF_INVALID; /*XXX*/
        vt_resume_flush_timer(vw->vw_device, 0);
 }
 
@@ -1181,6 +1171,13 @@ vtterm_cnprobe(struct terminal *tm, stru
                vt_compute_drawable_area(vw);
        }
 
+       /*
+        * The original screen size was faked (_VTDEFW x _VTDEFH). Now
+        * that we have the real viewable size, fix the it in the static
+        * buffer.
+        */
+       vt_termsize(vd, vw->vw_font, &vw->vw_buf.vb_scr_size);
+
        vtbuf_init_early(&vw->vw_buf);
        vt_winsize(vd, vw->vw_font, &wsz);
        c = (boothowto & RB_MUTE) == 0 ? TERMINAL_KERN_ATTR :
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to