Пример #1
0
/* Non-locking version of cons_vcons_scrollback.  Does also not update
   the display.  */
int
_cons_vcons_scrollback (vcons_t vcons, cons_scroll_t type, float value)
{
  int scrolling;
  uint32_t new_scr;

  switch (type)
    {
    case CONS_SCROLL_DELTA_LINES:
      scrolling = vcons->scrolling + ((uint32_t) value);
      break;
    case CONS_SCROLL_DELTA_SCREENS:
      scrolling = vcons->scrolling
	+ ((uint32_t) (value * vcons->state.screen.height));
      break;
    case CONS_SCROLL_ABSOLUTE_LINE:
      scrolling = (uint32_t) value;
      break;
    case CONS_SCROLL_ABSOLUTE_PERCENTAGE:
      scrolling = (uint32_t) (value * vcons->state.screen.scr_lines);
      break;
    default:
      return 0;
    }

  if (scrolling < 0)
    new_scr = 0;
  else if (scrolling > vcons->state.screen.scr_lines)
    new_scr = vcons->state.screen.scr_lines;
  else
    new_scr = scrolling;

  if (new_scr == vcons->scrolling)
    return 0;

  scrolling = vcons->scrolling - new_scr;
  {
    uint32_t new_cur_line;
    off_t size = vcons->state.screen.width
      * vcons->state.screen.lines;
    off_t vis_start;
    off_t start;
    off_t end;

    if (vcons->state.screen.cur_line >= new_scr)
      new_cur_line = vcons->state.screen.cur_line - new_scr;
    else
      new_cur_line = (UINT32_MAX - (new_scr - vcons->state.screen.cur_line)) + 1;

    if (scrolling > 0 && (uint32_t) scrolling > vcons->state.screen.height)
      scrolling = vcons->state.screen.height;
    else if (scrolling < 0
	     && (uint32_t) (-scrolling) > vcons->state.screen.height)
      scrolling = -vcons->state.screen.height;
    if ((scrolling > 0 && scrolling < vcons->state.screen.height)
	|| (scrolling < 0
	    && (uint32_t) (-scrolling) < vcons->state.screen.height))
      cons_vcons_scroll (vcons, scrolling);
    else if ((scrolling > 0 && scrolling == vcons->state.screen.height)
	|| (scrolling < 0
	    && (uint32_t) (-scrolling) == vcons->state.screen.height))
      cons_vcons_clear (vcons, vcons->state.screen.width
			* vcons->state.screen.height, 0, 0);

    vis_start = vcons->state.screen.width
      * (new_cur_line % vcons->state.screen.lines);
    if (scrolling > 0)
      start = (((new_cur_line % vcons->state.screen.lines)
		+ vcons->state.screen.height - scrolling)
	       * vcons->state.screen.width) % size;
    else
      start = vis_start;
    end = start + abs (scrolling) * vcons->state.screen.width - 1;

    cons_vcons_write (vcons,
		      vcons->state.screen.matrix + start,
		      end < size
		      ? end - start + 1 
		      : size - start,
		      0, (scrolling > 0)
		      ? vcons->state.screen.height - scrolling : 0);
    if (end >= size)
      cons_vcons_write (vcons,
			vcons->state.screen.matrix,
			end - size + 1,
			0, (size - vis_start)
			/ vcons->state.screen.width);
  }

  /* Set the new cursor position.  */
  {
    uint32_t row = vcons->state.cursor.row;
    uint32_t height = vcons->state.screen.height;

    if (row + new_scr < height)
      {
	cons_vcons_set_cursor_pos (vcons, vcons->state.cursor.col,
				   row + new_scr);
	if (row + vcons->scrolling >= height)
	  /* The cursor was invisible before.  */
	  cons_vcons_set_cursor_status (vcons, vcons->state.cursor.status);
      }
    else if (row + vcons->scrolling < height)
      /* The cursor was visible before.  */
      cons_vcons_set_cursor_status (vcons, CONS_CURSOR_INVISIBLE);
  }

  vcons->scrolling -= scrolling;

  return -scrolling;
}
Пример #2
0
kern_return_t
cons_S_file_changed (cons_notify_t notify, natural_t tickno,
		     file_changed_type_t change,
		     off_t start, off_t end)
{
  error_t err = 0;
  vcons_t vcons = (vcons_t) notify;

  if (!notify || notify->cons)
    return EOPNOTSUPP;

  mutex_lock (&vcons->lock);
  switch (change)
    {
    case FILE_CHANGED_NULL:
      /* Always sent first for sync.  */
      cons_vcons_refresh (vcons);
      break;
    case FILE_CHANGED_WRITE:
      /* File data has been written.  */
      while (vcons->state.changes.written < vcons->display->changes.written)
	{
	  cons_change_t change;
	  
	  if (vcons->display->changes.written - vcons->state.changes.written
	      > vcons->cons->slack)
	    {
	      cons_vcons_refresh (vcons);
	      continue;
	    }
	  change = vcons->state.changes.buffer[vcons->state.changes.written
					       % vcons->state.changes.length];
	  if (vcons->display->changes.written - vcons->state.changes.written
	      > vcons->state.changes.length - 1)
	    {
	      /* While we were reading the entry, the server might
		 have overwritten it.  */
	      cons_vcons_refresh (vcons);
	      continue;
	    }
	  vcons->state.changes.written++;

	  if (change.what.not_matrix)
	    {
	      if (change.what.cursor_pos)
		{
		  uint32_t old_row = vcons->state.cursor.row;
		  uint32_t height = vcons->state.screen.height;
		  uint32_t row;

		  vcons->state.cursor.col = vcons->display->cursor.col;
		  row = vcons->state.cursor.row = vcons->display->cursor.row;

		  if (row + vcons->scrolling < height)
		    {
		      cons_vcons_set_cursor_pos (vcons,
						 vcons->state.cursor.col,
						 row + vcons->scrolling);
		      if (old_row + vcons->scrolling >= height)
			/* The cursor was invisible before.  */
			cons_vcons_set_cursor_status (vcons,
						      vcons->state.cursor.status);
		    }
		  else if (old_row + vcons->scrolling < height)
		    /* The cursor was visible before.  */
		    cons_vcons_set_cursor_status (vcons, CONS_CURSOR_INVISIBLE);

		  _cons_vcons_console_event (vcons, CONS_EVT_OUTPUT);
		  cons_vcons_update (vcons);
		}
	      if (change.what.cursor_status)
		{
		  vcons->state.cursor.status = vcons->display->cursor.status;
		  cons_vcons_set_cursor_status (vcons,
						vcons->state.cursor.status);
		  cons_vcons_update (vcons);
		}
	      if (change.what.screen_cur_line)
		{
		  uint32_t new_cur_line;

		  new_cur_line = vcons->display->screen.cur_line;

		  if (new_cur_line != vcons->state.screen.cur_line)
		    {
		      off_t size = vcons->state.screen.width
			* vcons->state.screen.lines;
		      off_t vis_start;
		      uint32_t scrolling;
		      off_t start;
		      off_t end;
		      
		      if (new_cur_line > vcons->state.screen.cur_line)
			scrolling = new_cur_line
			  - vcons->state.screen.cur_line;
		      else
			scrolling = UINT32_MAX - vcons->state.screen.cur_line
			  + 1 + new_cur_line;

		      /* If we are scrolling back, defer scrolling
			 until absolutely necessary.  */
		      if (vcons->scrolling)
			{
			  if (_cons_jump_down_on_output)
			    _cons_vcons_scrollback
			      (vcons, CONS_SCROLL_ABSOLUTE_LINE, 0);
			  else
			    {
			      if (vcons->scrolling + scrolling
				  <= vcons->state.screen.scr_lines)
				{
				  vcons->scrolling += scrolling;
				  scrolling = 0;
				}
			      else
				{
				  scrolling -= vcons->state.screen.scr_lines
				    - vcons->scrolling;
				  vcons->scrolling
				    = vcons->state.screen.scr_lines;
				}
			    }
			}

		      if (scrolling)
			{
			  uint32_t cur_disp_line;

			  if (new_cur_line >= vcons->scrolling)
			    cur_disp_line = new_cur_line - vcons->scrolling;
			  else
			    cur_disp_line = (UINT32_MAX - (vcons->scrolling - new_cur_line)) + 1;

			  if (scrolling > vcons->state.screen.height)
			    scrolling = vcons->state.screen.height;
			  if (scrolling < vcons->state.screen.height)
			    cons_vcons_scroll (vcons, scrolling);
			  else
			    cons_vcons_clear (vcons, vcons->state.screen.width
					      * vcons->state.screen.height,
					      0, 0);
			  vis_start = vcons->state.screen.width
			    * (cur_disp_line % vcons->state.screen.lines);
			  start = (((cur_disp_line % vcons->state.screen.lines)
				    + vcons->state.screen.height - scrolling)
				   * vcons->state.screen.width) % size;
			  end = start + scrolling * vcons->state.screen.width - 1;
			  cons_vcons_write (vcons,
					    vcons->state.screen.matrix + start,
					    end < size
					    ? end - start + 1 
					    : size - start,
					    0, vcons->state.screen.height
					    - scrolling);
			  if (end >= size)
			    cons_vcons_write (vcons,
					      vcons->state.screen.matrix,
					      end - size + 1,
					      0, (size - vis_start)
					      / vcons->state.screen.width);
			  _cons_vcons_console_event (vcons, CONS_EVT_OUTPUT);
			  cons_vcons_update (vcons);
			}
		      vcons->state.screen.cur_line = new_cur_line;
		    }
		}
	      if (change.what.screen_scr_lines)
		{
		  vcons->state.screen.scr_lines
		    = vcons->display->screen.scr_lines;
		  if (vcons->state.screen.scr_lines < vcons->scrolling)
		    assert (!"Implement shrinking scrollback buffer! XXX");
		}
	      if (change.what.bell_audible)
		{
		  while (vcons->state.bell.audible
			 < vcons->display->bell.audible)
		    {
		      if (_cons_audible_bell == BELL_AUDIBLE)
			cons_vcons_beep (vcons);
		      else if (_cons_audible_bell == BELL_VISUAL)
			cons_vcons_flash (vcons);
		      vcons->state.bell.audible++;
		    }
		}
	      if (change.what.bell_visible)
		{
		  while (vcons->state.bell.visible
			 < vcons->display->bell.visible)
		    {
		      if (_cons_visual_bell == BELL_VISUAL)
			cons_vcons_flash (vcons);
		      else if (_cons_visual_bell == BELL_AUDIBLE)
			cons_vcons_beep (vcons);
		      vcons->state.bell.visible++;
		    }
		}
	      if (change.what.flags)
		{
		  uint32_t flags = vcons->display->flags;

		  if ((flags & CONS_FLAGS_SCROLL_LOCK)
		      != (vcons->state.flags & CONS_FLAGS_SCROLL_LOCK))
		    cons_vcons_set_scroll_lock (vcons, flags
						& CONS_FLAGS_SCROLL_LOCK);
		  vcons->state.flags = flags;
		}
	    }
	  else
	    {
	      /* For clipping.  */
	      off_t size = vcons->state.screen.width*vcons->state.screen.lines;
	      off_t rotate;
	      off_t vis_end = vcons->state.screen.height
		* vcons->state.screen.width - 1;
	      off_t end2 = -1;
	      off_t start_rel = 0;    /* start relative to visible start.  */
	      off_t start = change.matrix.start;
	      off_t end = change.matrix.end;

	      if (vcons->scrolling && _cons_jump_down_on_output)
		_cons_vcons_scrollback (vcons, CONS_SCROLL_ABSOLUTE_LINE, 0);

	      if (vcons->state.screen.cur_line >= vcons->scrolling)
		rotate = vcons->state.screen.cur_line - vcons->scrolling;
	      else
		rotate = (UINT32_MAX - (vcons->scrolling - vcons->state.screen.cur_line)) + 1;
	      rotate = vcons->state.screen.width * (rotate % vcons->state.screen.lines);

	      /* Rotate the buffer.  */
	      start -= rotate;
	      if (start < 0)
		start += size;
	      end -= rotate;
	      if (end < 0)
		end += size;
	      
	      /* Find the intersection.  */
	      if (start > vis_end)
		{
		  if (end < start)
		    {
		      start = 0;
		      if (vis_end < end)
			end = vis_end;
		    }
		  else
		    start = -1;
		}
	      else
		{
		  if (end >= start)
		    {
		      if (end > vis_end)
			end = vis_end;
		    }
		  else
		    {
		      end2 = end;
		      end = vis_end;
		    }
		}
	      /* We now have three cases: No intersection if start ==
		 -1, one intersection [start;end] if end2 == -1, and
		 two intersections [start;end] and [0;end2] if end2 !=
		 -1.  However, we still have to undo the buffer
		 rotation.  */
	      if (start != -1)
		{
		  start_rel = start;
		  start += rotate;
		  if (start >= size)
		    start -= size;
		  end += rotate;
		  if (end >= size)
		    end -= size;
		  if (start > end)
		    end += size;
		}
	      if (end2 != -1)
		/* The interval should be [vis_start:end2].  */
		end2 += rotate;
	      
	      if (start != -1)
		{
		  cons_vcons_clear (vcons, end - start + 1,
				    start_rel % vcons->state.screen.width,
				    start_rel / vcons->state.screen.width);
		  cons_vcons_write (vcons, vcons->state.screen.matrix + start,
				    end < size
				    ? end - start + 1
				    : size - start,
				    start_rel % vcons->state.screen.width,
				    start_rel / vcons->state.screen.width);
		  if (end >= size)
		    cons_vcons_write (vcons, vcons->state.screen.matrix,
				      end - size + 1,
				      (size - rotate)
				      % vcons->state.screen.width,
				      (size - rotate)
				      / vcons->state.screen.width);
		  if (end2 != -1)
		    {
		      cons_vcons_clear (vcons, end2 - rotate + 1, 0, 0);
		      cons_vcons_write (vcons,
					vcons->state.screen.matrix + rotate,
					end2 < size
					? end2 - rotate + 1
					: size - rotate,
					0, 0);
		      if (end2 >= size)
			cons_vcons_write (vcons, vcons->state.screen.matrix,
					  end2 - size + 1,
					  (size - rotate)
					  % vcons->state.screen.width,
					  (size - rotate)
					  / vcons->state.screen.width);
		    }
		  _cons_vcons_console_event (vcons, CONS_EVT_OUTPUT);
		  cons_vcons_update (vcons);
		}
	    }
	}
      break;
    case FILE_CHANGED_EXTEND:
      /* File has grown.  */
    case FILE_CHANGED_TRUNCATE:
      /* File has been truncated.  */
    case FILE_CHANGED_META:
      /* Stat information has changed, and none of the previous three
	 apply.  Not sent for changes in node times.  */
    default:
      err = EINVAL;
    };

  mutex_unlock (&vcons->lock);
  return err;
}