summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordumbbell <dumbbell@FreeBSD.org>2014-09-19 12:20:43 +0000
committerdumbbell <dumbbell@FreeBSD.org>2014-09-19 12:20:43 +0000
commitbd0370dde72628f204a806b4331389643b03ce6a (patch)
tree04d7516435fce667e7c74014dfbb0d38669c71fb
parent99f4bfa07bbcb4fe4d7dfc7d535785f2675d9de8 (diff)
downloadFreeBSD-src-bd0370dde72628f204a806b4331389643b03ce6a.zip
FreeBSD-src-bd0370dde72628f204a806b4331389643b03ce6a.tar.gz
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
-rw-r--r--sys/dev/vt/vt_buf.c240
-rw-r--r--sys/dev/vt/vt_core.c19
2 files changed, 172 insertions, 87 deletions
diff --git a/sys/dev/vt/vt_buf.c b/sys/dev/vt/vt_buf.c
index 0c184ec..91ebba3 100644
--- a/sys/dev/vt/vt_buf.c
+++ b/sys/dev/vt/vt_buf.c
@@ -76,44 +76,46 @@ vthistory_seek(struct vt_buf *vb, int offset, int whence)
}
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, int offset)
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, int size)
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_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));
- /* 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);
-
- /* 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
diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c
index 8f2e245..81f4d3e 100644
--- a/sys/dev/vt/vt_core.c
+++ b/sys/dev/vt/vt_core.c
@@ -484,18 +484,8 @@ vt_scroll(struct vt_window *vw, int offset, int whence)
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, struct consdev *cp)
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 :
OpenPOWER on IntegriCloud