From ccc4092e238c5e074a32e2c5794ab01934f272df Mon Sep 17 00:00:00 2001
From: Marcus Brinkmann <marcus@gnu.org>
Date: Thu, 13 Jun 2002 00:24:26 +0000
Subject: 2002-06-13  Marcus Brinkmann  <marcus@gnu.org>

	* Makefile (DIST_FILES): New target.
	(MIGSTUBS): Likewise.
	(OBJS): Add $(MIGSTUBS).
	* ourfs_notify.defs: New file.
	* console.c: Diddle order of typedefs.
	(netfs_attempt_read): Clip AMT to bytes left to read before
	calling display_read.
	(netfs_S_file_notice_changes): New function.
	* console.h: Include <stdint.h>, not <sys/types.h>.
	Change all types from u_int32_t to uint32_t.
	* display.c: Include <stddef.h> and "outfs_notify_U.h".  Change
	all u_int_32 types to uint32_t.
	(struct modreq): New structure.
	(struct display): New member filemod_reqs.
	(free_modreqs): New function.
	(display_notice_changes): Likewise.
	(display_notice_filechange): Likewise.
	(display_destroy): Free filemod_reqs member of DISPLAY.
	(MATRIX_POS): Macro removed.
	(screen_fill): Rewritten.
	(screen_shift_left): New function.
	(screen_shift_right): Likewise.
	(screen_scroll_up): Function removed.
	(screen_scroll_down): Likewise.
	(screen_scroll_left): Likewise.
	(screen_scroll_right): Likewise.
	(handle_esc_bracket): Use new screen_* functions.
	(display_output_one): Store old cursor and screen attributes, and
	if they have been changed, send file change notifications.
	* display.h: New prototype for display_notice_changes.
---
 console/ChangeLog         |  33 ++++
 console/Makefile          |   5 +-
 console/console.c         |  41 +++--
 console/console.h         |  26 ++--
 console/display.c         | 376 +++++++++++++++++++++++++++++++---------------
 console/display.h         |   2 +
 console/ourfs_notify.defs |   5 +
 7 files changed, 343 insertions(+), 145 deletions(-)
 create mode 100644 console/ourfs_notify.defs

(limited to 'console')

diff --git a/console/ChangeLog b/console/ChangeLog
index 53fa34a8..54fa609c 100644
--- a/console/ChangeLog
+++ b/console/ChangeLog
@@ -1,3 +1,36 @@
+2002-06-13  Marcus Brinkmann  <marcus@gnu.org>
+
+	* Makefile (DIST_FILES): New target.
+	(MIGSTUBS): Likewise.
+	(OBJS): Add $(MIGSTUBS).
+	* ourfs_notify.defs: New file.
+	* console.c: Diddle order of typedefs.
+	(netfs_attempt_read): Clip AMT to bytes left to read before
+	calling display_read.
+	(netfs_S_file_notice_changes): New function.
+	* console.h: Include <stdint.h>, not <sys/types.h>.
+	Change all types from u_int32_t to uint32_t.
+	* display.c: Include <stddef.h> and "outfs_notify_U.h".  Change
+	all u_int_32 types to uint32_t.
+	(struct modreq): New structure.
+	(struct display): New member filemod_reqs.
+	(free_modreqs): New function.
+	(display_notice_changes): Likewise.
+	(display_notice_filechange): Likewise.
+	(display_destroy): Free filemod_reqs member of DISPLAY.
+	(MATRIX_POS): Macro removed.
+	(screen_fill): Rewritten.
+	(screen_shift_left): New function.
+	(screen_shift_right): Likewise.
+	(screen_scroll_up): Function removed.
+	(screen_scroll_down): Likewise.
+	(screen_scroll_left): Likewise.
+	(screen_scroll_right): Likewise.
+	(handle_esc_bracket): Use new screen_* functions.
+	(display_output_one): Store old cursor and screen attributes, and
+	if they have been changed, send file change notifications.
+	* display.h: New prototype for display_notice_changes.
+
 2002-06-12  Marcus Brinkmann  <marcus@gnu.org>
 
 	* console.c: Include <argz.h>.  Do not include "console.h", but
diff --git a/console/Makefile b/console/Makefile
index 2e227269..2f15f1a1 100644
--- a/console/Makefile
+++ b/console/Makefile
@@ -25,9 +25,12 @@ target = console
 
 SRCS = console.c display.c input.c
 LCLHDRS = console.h display.h input.h
+DIST_FILES = ourfs_notify.defs
+
+MIGSTUBS = ourfs_notifyUser.o
 
 HURDLIBS = netfs fshelp iohelp threads ports ihash shouldbeinlibc
-OBJS = $(subst .c,.o,$(SRCS))
+OBJS = $(sort $(SRCS:.c=.o) $(MIGSTUBS))
 
 # This is the old monolithic version of the console server.
 #SRCS = main.c vcons.c focus.c vga-display.c vga.c dynafont.c bdf.c
diff --git a/console/console.c b/console/console.c
index 3c1c5ce2..7d12db9f 100644
--- a/console/console.c
+++ b/console/console.c
@@ -52,6 +52,12 @@ volatile struct mapped_time_value *console_maptime;
 #define DEFAULT_ENCODING "ISO-8859-1"
 
 
+/* A handle for a console device.  */
+typedef struct cons *cons_t;
+
+/* A handle for a virtual console device.  */
+typedef struct vcons *vcons_t;
+
 struct vcons
 {
   /* Protected by cons->lock.  */
@@ -75,8 +81,6 @@ struct vcons
   struct node *disp_node;
   struct node *inpt_node;
 };
-/* A handle for a virtual console device.  */
-typedef struct vcons *vcons_t;
 
 struct cons
 {
@@ -93,8 +97,6 @@ struct cons
   /* A template for the stat information of all nodes.  */
   struct stat stat_template;
 };
-/* A handle for a console device.  */
-typedef struct cons *cons_t;
 
 
 /* Lookup the virtual console with number ID in the console CONS,
@@ -1051,11 +1053,14 @@ netfs_attempt_read (struct iouser *cred, struct node *np,
       ssize_t amt = *len;
       assert (np == vcons->disp_node);
 
-      if (amt > np->nn_stat.st_size)
-	amt = np->nn_stat.st_size;
-      amt = display_read (vcons->display,
-			  /* cred->po->openstat & O_NONBLOCK */ 0,
-			  offset, data, amt);
+      if (offset + amt > np->nn_stat.st_size)
+	amt = np->nn_stat.st_size - offset;
+      if (amt < 0)
+	amt = 0;
+      else
+	amt = display_read (vcons->display,
+			    /* cred->po->openstat & O_NONBLOCK */ 0,
+			    offset, data, amt);
       if (amt == -1)
 	err = errno;
       else
@@ -1165,6 +1170,24 @@ netfs_S_io_map (struct protid *cred,
   return errno;
 }
 
+
+kern_return_t
+netfs_S_file_notice_changes (struct protid *cred, mach_port_t notify)
+{
+  struct node *np;
+  vcons_t vcons;
+
+  if (!cred)
+    return EOPNOTSUPP;
+
+  np = cred->po->np;
+  vcons = np->nn->vcons;
+  if (!vcons || np != vcons->disp_node)
+    return EOPNOTSUPP;
+
+  return display_notice_changes (vcons->display, notify);
+}
+
 
 static const struct argp_option options[] =
 {
diff --git a/console/console.h b/console/console.h
index 27996955..08f35955 100644
--- a/console/console.h
+++ b/console/console.h
@@ -19,41 +19,43 @@
 #ifndef _HURD_CONSOLE_H
 #define _HURD_CONSOLE_H
 
-#include <sys/types.h>
+#include <stdint.h>
 
 struct cons_display
 {
 #define CONS_MAGIC 0x48555244	/* Hex for "HURD".  */
-  u_int32_t magic;		/* CONS_MAGIC, use to detect
+  uint32_t magic;		/* CONS_MAGIC, use to detect
 				   endianess.  */
 #define CONS_VERSION_MAJ 0x0
 #define CONS_VERSION_MAJ_SHIFT 16
 #define CONS_VERSION_AGE 0x0
-  u_int32_t version;		/* Version of interface.  Lower 16
+  uint32_t version;		/* Version of interface.  Lower 16
 				   bits define the age, upper 16 bits
 				   the major version.  */
   struct
   {
-    u_int32_t width;	/* Width of screen matrix.  */
-    u_int32_t lines;	/* Length of whole matrix.  */
-    u_int32_t cur_line;	/* Beginning of visible area.  */
-    u_int32_t scr_lines;/* Number of lines in scrollback buffer
+    uint32_t width;	/* Width of screen matrix.  */
+    uint32_t lines;	/* Length of whole matrix.  */
+    uint32_t cur_line;	/* Beginning of visible area.  This is only
+			   ever increased by the server, so clients
+			   can optimize scrolling.  */
+    uint32_t scr_lines;/* Number of lines in scrollback buffer
 			   preceeding CUR_LINE.  */
-    u_int32_t height;	/* Number of lines in visible area following
+    uint32_t height;	/* Number of lines in visible area following
 			   (and including) CUR_LINE.  */
-    u_int32_t matrix;	/* Index (in wchar_t) of the beginning of
+    uint32_t matrix;	/* Index (in wchar_t) of the beginning of
 			   screen matrix in this structure.  */
   } screen;
 
   struct
   {
-    u_int32_t col;	/* Current column (x-position) of cursor.  */
-    u_int32_t row;	/* Current row (y-position) of cursor.  */
+    uint32_t col;	/* Current column (x-position) of cursor.  */
+    uint32_t row;	/* Current row (y-position) of cursor.  */
 
 #define CONS_CURSOR_INVISIBLE 0
 #define CONS_CURSOR_NORMAL 1
 #define CONS_CURSOR_VERY_VISIBLE 2
-    u_int32_t status;	/* Visibility status of cursor.  */
+    uint32_t status;	/* Visibility status of cursor.  */
   } cursor;
 
   /* Don't use this, use ((wchar_t *) cons_display +
diff --git a/console/display.c b/console/display.c
index 9c33b933..fe2dc4f0 100644
--- a/console/display.c
+++ b/console/display.c
@@ -18,6 +18,7 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA. */
 
+#include <stddef.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <unistd.h>
@@ -36,6 +37,8 @@
 #include <hurd.h>
 #include <hurd/pager.h>
 
+#include "ourfs_notify_U.h"
+
 #ifndef __STDC_ISO_10646__
 #error It is required that wchar_t is UCS-4.
 #endif
@@ -46,8 +49,8 @@
 
 struct cursor
 {
-  u_int32_t saved_x;
-  u_int32_t saved_y;
+  uint32_t saved_x;
+  uint32_t saved_y;
 };
 typedef struct cursor *cursor_t;
 
@@ -114,6 +117,13 @@ struct user_pager_info
   struct pager *p;
 };
 
+/* Pending directory and file modification requests.  */
+struct modreq
+{
+  mach_port_t port;
+  struct modreq *next;
+};
+
 struct display
 {
   /* The lock for the virtual console display structure.  */
@@ -133,6 +143,9 @@ struct display
   struct user_pager_info *upi;  
   memory_object_t memobj;
   size_t memobj_size;
+
+  /* A list of ports to send file change notifications to.  */
+  struct modreq *filemod_reqs;
 };
 
 
@@ -159,8 +172,6 @@ pager_clear_user_data (struct user_pager_info *upi)
   free (upi);
 }
 
-/* XXX This is not good enough.  We actually need to provide a backing
-   store.  */
 error_t
 pager_read_page (struct user_pager_info *pager, vm_offset_t page,
                  vm_address_t *buf, int *writelock)
@@ -178,7 +189,8 @@ pager_write_page (struct user_pager_info *pager,
                   vm_offset_t page,
                   vm_address_t buf)
 {
-  /* XXX Implement me.  */
+  /* XXX Implement me.  Just store away the page, and release it when
+     releasing the pager.  */
   assert (0);
 }
 
@@ -219,15 +231,80 @@ service_paging_requests (any_t arg)
                                               1000 * 60 * 10, 0);
 }    
 
+
+/* Free the list of modification requests MR */
+static void
+free_modreqs (struct modreq *mr)
+{
+  struct modreq *tmp;
+  for (; mr; mr = tmp)
+    {
+      mach_port_deallocate (mach_task_self (), mr->port);
+      tmp = mr->next;
+      free (mr);
+    }
+}
+
+error_t
+display_notice_changes (display_t display, mach_port_t notify)
+{
+  error_t err;
+  struct modreq *req;
+
+  mutex_lock (&display->lock);
+  err = nowait_file_changed (notify, FILE_CHANGED_NULL, 0, 0);
+  if (err)
+    {
+      mutex_unlock (&display->lock);
+      return err;
+    }
+  req = malloc (sizeof (struct modreq));
+  if (!req)
+    {
+      mutex_unlock (&display->lock);
+      return errno;
+    }
+  req->port = notify;
+  req->next = display->filemod_reqs;
+  display->filemod_reqs = req;
+  mutex_unlock (&display->lock);
+  return 0;
+}
+
+/* Requires DISPLAY to be locked.  */
+void
+display_notice_filechange (display_t display, enum file_changed_type type,
+			   off_t start, off_t end)
+{
+  error_t err;
+  struct modreq **preq;
+
+  preq = &display->filemod_reqs;
+  while (*preq)
+    {
+      struct modreq *req = *preq;
+      err = nowait_file_changed (req->port, type, start, end);
+      if (err)
+        {
+	  /* Remove notify port.  */
+          *preq = req->next;
+          mach_port_deallocate (mach_task_self (), req->port);
+          free (req);
+        }
+      else
+        preq = &req->next;
+    }
+}
+
 
 static error_t
-user_create (display_t display, u_int32_t width, u_int32_t height,
-	     u_int32_t lines)
+user_create (display_t display, uint32_t width, uint32_t height,
+	     uint32_t lines)
 {
   error_t err;
   struct cons_display *user;
   display->memobj_size = round_page (sizeof (struct cons_display) +
-				   sizeof (u_int32_t) * width * lines);
+				   sizeof (uint32_t) * width * lines);
 
   display->upi = malloc (sizeof (struct user_pager_info));
   if (!display->upi)
@@ -270,7 +347,7 @@ user_create (display_t display, u_int32_t width, u_int32_t height,
   user->screen.lines = lines;
   user->screen.cur_line = 0;
   user->screen.scr_lines = 0;
-  user->screen.matrix = sizeof (struct cons_display) / sizeof (u_int32_t);
+  user->screen.matrix = sizeof (struct cons_display) / sizeof (uint32_t);
   user->cursor.col = 0;
   user->cursor.row = 0;
   user->cursor.status = CONS_CURSOR_NORMAL;
@@ -289,103 +366,124 @@ user_destroy (display_t display)
 }
 
 
-#define MATRIX_POS(user,x,y) ((user)->_matrix \
-    + (((user)->screen.cur_line + (y)) % (user)->screen.height) \
-    * (user)->screen.width + (x))
-
 static void
-screen_fill (display_t display, size_t x, size_t y, size_t w, size_t h,
-	     wchar_t chr, char attr)
+screen_fill (display_t display, size_t col1, size_t row1, size_t col2,
+	     size_t row2, wchar_t chr, char attr)
 {
   struct cons_display *user = display->user;
-  wchar_t *matrixp = MATRIX_POS (user, x, y);
+  off_t start = (user->screen.cur_line + row1) * user->screen.width + col1;
+  off_t end = (user->screen.cur_line + row2) * user->screen.width + col2;
+  off_t size = user->screen.width * user->screen.lines;
 
-  while (h--)
+  if (start >= size && end >= size)
     {
-      /* XXX Set attribute flags.  */
-      wmemset (matrixp, L' ', w);
-      matrixp += user->screen.width;
+      start -= size;
+      end -= size;
     }
 
-  /* XXX Flag screen change, but here or where else?  */
-}
-
-static void
-screen_scroll_up (display_t display, size_t x, size_t y, size_t w, size_t h,
-		  int amt, wchar_t chr, char attr)
-{
-  struct cons_display *user = display->user;
-  wchar_t *matrixp = MATRIX_POS (user, x, y);
-
-  if (amt < 0)
-    return;
-
-  while (h-- > amt)
+  if (end < size)
     {
-      wmemcpy (matrixp, matrixp + amt * user->screen.width, w);
-      matrixp += user->screen.width;
+      wmemset (user->_matrix + start, chr, end - start + 1);
+      display_notice_filechange (display, FILE_CHANGED_WRITE,
+				 sizeof (struct cons_display)
+				 + start * sizeof (wchar_t),
+				 sizeof (struct cons_display)
+				 + (end + 1) * sizeof (wchar_t) - 1);
     }
-  screen_fill (display, x, y, w, h, chr, attr);
-}
-
-static void
-screen_scroll_down (display_t display, size_t x, size_t y, size_t w, size_t h,
-		    int amt, wchar_t chr, char attr)
-{
-  struct cons_display *user = display->user;
-  wchar_t *matrixp = MATRIX_POS (user, x, y + h - 1);
-
-  if (amt < 0)
-    return;
-
-  while (h-- > amt)
+  else
     {
-      wmemcpy (matrixp, matrixp - amt * user->screen.width, w);
-      matrixp -= user->screen.width;
+      wmemset (user->_matrix + start, chr, size - start);
+      wmemset (user->_matrix, chr, end - size + 1);
+      display_notice_filechange (display, FILE_CHANGED_WRITE,
+				 sizeof (struct cons_display)
+				 + start * sizeof (wchar_t),
+				 sizeof (struct cons_display)
+				 + (end - size + 1) * sizeof (wchar_t) - 1);
     }
-  screen_fill (display, x, y, w, h, chr, attr);
 }
 
 static void
-screen_scroll_left (display_t display, size_t x, size_t y, size_t w, size_t h,
-		    int amt, wchar_t chr, char attr)
+screen_shift_left (display_t display, size_t row1, size_t col1, size_t row2,
+		   size_t col2, size_t shift, wchar_t chr, char attr)
 {
   struct cons_display *user = display->user;
-  wchar_t *matrixp = MATRIX_POS (user, x, y);
-  int i;
+  off_t start = (user->screen.cur_line + row1) * user->screen.width + col1;
+  off_t end = (user->screen.cur_line + row2) * user->screen.width + col2;
+  off_t size = user->screen.width * user->screen.lines;
 
-  if (amt < 0)
-    return;
-  if (amt > w)
-    amt = w;
+  if (start >= size && end >= size)
+    {
+      start -= size;
+      end -= size;
+    }
 
-  for (i = 0; i < y + h; i++)
+  if (start + shift <= end)
     {
-      wmemmove (matrixp, matrixp + amt, w - amt);
-      matrixp += user->screen.width;
+      /* Use a loop to copy the data.  Using wmemmove and wmemset on
+	 the chunks is tiresome, as there are many cases.  */
+      off_t src = start + shift;
+      off_t dst = start;
+
+      while (src <= end)
+	user->_matrix[dst++ % size] = user->_matrix[src++ % size];
+      while (dst <= end)
+	user->_matrix[dst++ % size] = chr;
+
+      display_notice_filechange (display, FILE_CHANGED_TRUNCATE,
+				 sizeof (struct cons_display)
+				 + start * sizeof (wchar_t),
+				 sizeof (struct cons_display)
+				 + (start + shift) * sizeof (wchar_t) - 1);
+      display_notice_filechange (display, FILE_CHANGED_EXTEND,
+				 sizeof (struct cons_display)
+				 + (end - shift + 1) * sizeof (wchar_t),
+				 sizeof (struct cons_display)
+				 + (end + 1) * sizeof (wchar_t) - 1);
     }
-  screen_fill (display, x + w - amt, y, amt, h, chr, attr);
+  else
+    screen_fill (display, col1, row1, col2, row2, chr, attr);
 }
 
 static void
-screen_scroll_right (display_t display, size_t x, size_t y, size_t w, size_t h,
-		     int amt, wchar_t chr, char attr)
+screen_shift_right (display_t display, size_t row1, size_t col1, size_t row2,
+		    size_t col2, size_t shift, wchar_t chr, char attr)
 {
   struct cons_display *user = display->user;
-  wchar_t *matrixp = MATRIX_POS (user, x, y);
-  int i;
+  off_t start = (user->screen.cur_line + row1) * user->screen.width + col1;
+  off_t end = (user->screen.cur_line + row2) * user->screen.width + col2;
+  off_t size = user->screen.width * user->screen.lines;
 
-  if (amt < 0)
-    return;
-  if (amt > w)
-    amt = w;
+  if (start >= size && end >= size)
+    {
+      start -= size;
+      end -= size;
+    }
 
-  for (i = 0; i < y + h; i++)
+  if (start + shift <= end)
     {
-      wmemmove (matrixp + amt, matrixp, w - amt);
-      matrixp += user->screen.width;
+      /* Use a loop to copy the data.  Using wmemmove and wmemset on
+	 the chunks is tiresome, as there are many cases.  */
+      off_t src = end - shift;
+      off_t dst = end;
+
+      while (src >= start)
+	user->_matrix[dst-- % size] = user->_matrix[src-- % size];
+      while (dst >= start)
+	user->_matrix[dst-- % size] = chr;
+
+      display_notice_filechange (display, FILE_CHANGED_EXTEND,
+				 sizeof (struct cons_display)
+				 + start * sizeof (wchar_t),
+				 sizeof (struct cons_display)
+				 + (start + shift) * sizeof (wchar_t) - 1);
+      display_notice_filechange (display, FILE_CHANGED_TRUNCATE,
+				 sizeof (struct cons_display)
+				 + (end - shift + 1) * sizeof (wchar_t),
+				 sizeof (struct cons_display)
+				 + (end + 1) * sizeof (wchar_t) - 1);
     }
-  screen_fill (display, x, y, amt, h, chr, attr);
+  else
+    screen_fill (display, col1, row1, col2, row2, chr, attr);
 }
 
 
@@ -607,26 +705,19 @@ handle_esc_bracket (display_t display, char op)
 	case 0:
 	  /* Clear to end of screen: <ed>.  */
 	  screen_fill (display, user->cursor.col, user->cursor.row,
-		       user->screen.width - user->cursor.col, 1, L' ',
-		       display->attr.current);
-	  screen_fill (display, 0, user->cursor.row + 1,
-		       user->screen.width,
-		       user->screen.height - user->cursor.row,
-			L' ', display->attr.current);
+		       user->screen.width - 1, user->screen.height - 1,
+		       L' ', display->attr.current);
 	  break;
 	case 1:
 	  /* Clear to beginning of screen.  */
 	  screen_fill (display, 0, 0,
-		       user->screen.width, user->cursor.row,
-		       L' ', display->attr.current);
-	  screen_fill (display, 0, user->cursor.row,
-		       user->cursor.col + 1, 1,
+		       user->cursor.col, user->cursor.row,
 		       L' ', display->attr.current);
 	  break;
 	case 2:
 	  /* Clear entire screen.  */
 	  screen_fill (display, 0, 0,
-		       user->screen.width, user->screen.height,
+		       user->screen.width - 1, user->screen.height - 1,
 		       L' ', display->attr.current);
 	  break;
 	}
@@ -637,73 +728,70 @@ handle_esc_bracket (display_t display, char op)
 	case 0:
 	  /* Clear to end of line: <el>.  */
 	  screen_fill (display, user->cursor.col, user->cursor.row,
-		       user->screen.width - user->cursor.col, 1,
+		       user->screen.width - 1, user->cursor.row,
 		       L' ', display->attr.current);
 	  break;
 	case 1:
 	  /* Clear to beginning of line: <el1>.  */
 	  screen_fill (display, 0, user->cursor.row,
-		       user->cursor.col + 1, 1,
+		       user->cursor.col, user->cursor.row,
 		       L' ', display->attr.current);
 	  break;
 	case 2:
 	  /* Clear entire line.  */
 	  screen_fill (display, 0, user->cursor.row,
-		       user->screen.width, 1,
+		       user->screen.width - 1, user->cursor.row,
 		       L' ', display->attr.current);
 	  break;
 	}
       break;
     case 'L':
       /* Insert line(s): <il1>, <il>.  */
-      screen_scroll_down (display, 0, user->cursor.row,
-			  user->screen.width,
-			  user->screen.height - user->cursor.row,
-			  parse->params[0] ?: 1,
+      screen_shift_right (display, 0, user->cursor.row,
+			  user->screen.width - 1, user->screen.height - 1,
+			  (parse->params[0] ?: 1) * user->screen.width,
 			  L' ', display->attr.current);
       break;
     case 'M':
       /* Delete line(s): <dl1>, <dl>.  */
-      screen_scroll_up (display, 0, user->cursor.row,
-			user->screen.width,
-			user->screen.height - user->cursor.row,
-			parse->params[0] ?: 1,
-			L' ', display->attr.current);
+      screen_shift_left (display, 0, user->cursor.row,
+			 user->screen.width - 1, user->screen.height - 1,
+			 (parse->params[0] ?: 1) * user->screen.width,
+			 L' ', display->attr.current);
       break;
     case '@':
       /* Insert character(s): <ich1>, <ich>.  */
-      screen_scroll_right (display, user->cursor.col,
-			   user->cursor.row,
-			   user->screen.width - user->cursor.col, 1,
-			   parse->params[0] ?: 1,
-			   L' ', display->attr.current);
+      screen_shift_right (display, user->cursor.col, user->cursor.row,
+			  user->screen.width - 1, user->cursor.row,
+			  parse->params[0] ?: 1,
+			  L' ', display->attr.current);
       break;
     case 'P':
       /* Delete character(s): <dch1>, <dch>.  */
-      screen_scroll_left (display, user->cursor.col,
-			  user->cursor.row,
-			  user->screen.width - user->cursor.col, 1,
-			  parse->params[0] ?: 1,
-			  L' ', display->attr.current);
+      screen_shift_left (display, user->cursor.col, user->cursor.row,
+			 user->screen.width - 1, user->cursor.row,
+			 parse->params[0] ?: 1,
+			 L' ', display->attr.current);
       break;
     case 'S':
       /* Scroll up: <ind>, <indn>.  */
-      screen_scroll_up (display, 0, 0,
-			user->screen.width, user->screen.height,
-			parse->params[0] ?: 1,
-			L' ', display->attr.current);
+      screen_shift_left (display, 0, 0,
+			 user->screen.width - 1, user->screen.height - 1,
+			 (parse->params[0] ?: 1) * user->screen.width,
+			 L' ', display->attr.current);
       break;
     case 'T':
       /* Scroll down: <ri>, <rin>.  */
-      screen_scroll_down (display, 0, 0,
+      screen_shift_right (display, 0, 0,
 			  user->screen.width, user->screen.height,
-			  parse->params[0] ?: 1,
+			  (parse->params[0] ?: 1) * user->screen.width,
 			  L' ', display->attr.current);
       break;
     case 'X':
       /* Erase character(s): <ech>.  */
       screen_fill (display, user->cursor.col, user->cursor.row,
-		   parse->params[0] ?: 1, 1,
+		   /* XXX limit ? */user->cursor.col + parse->params[0] ?: 1,
+		   user->cursor.row,
 		   L' ', display->attr.current);
       break;
     }
@@ -754,6 +842,12 @@ display_output_one (display_t display, wchar_t chr)
   struct cons_display *user = display->user;
   parse_t parse = &display->output.parse;
 
+  uint32_t old_cursor_col = user->cursor.col;
+  uint32_t old_cursor_row = user->cursor.row;
+  uint32_t old_cursor_status = user->cursor.status;
+  uint32_t old_cur_line = user->screen.cur_line;
+  uint32_t old_scr_lines = user->screen.scr_lines;
+
   void newline (void)
     {
       if (user->cursor.row < user->screen.height - 1)
@@ -768,12 +862,12 @@ display_output_one (display_t display, wchar_t chr)
 
 	  /* XXX Set attribute flags.  */
 	  screen_fill (display, 0, user->screen.height - 1,
-		       user->screen.width, 1, L' ', user->screen.width);
+		       user->screen.width - 1, user->screen.height - 1,
+		       L' ', user->screen.width);
 	  if (user->screen.scr_lines <
 	      user->screen.lines - user->screen.height)
 	    user->screen.scr_lines++;
 	  /* XXX Flag current line change.  */
-	  /* XXX Flag change of last line.  */
 	  /* XXX Possibly flag change of length of scroll back buffer.  */
 	}
     }
@@ -831,10 +925,15 @@ display_output_one (display_t display, wchar_t chr)
 	  {
 	    int line = (user->screen.cur_line + user->cursor.row)
 	      % user->screen.lines;
-
+	    int idx = line * user->screen.width + user->cursor.col;
 	    /* XXX Set attribute flags.  */
-	    user->_matrix[line * user->screen.width
-			  + user->cursor.col] = chr;
+	    user->_matrix[idx] = chr;
+
+	    display_notice_filechange (display, FILE_CHANGED_WRITE,
+				       sizeof (struct cons_display)
+				       + idx * sizeof (wchar_t),
+				       sizeof (struct cons_display)
+				       + (idx + 1) * sizeof (wchar_t) - 1);
 
 	    user->cursor.col++;
 	    if (user->cursor.col == user->screen.width)
@@ -856,7 +955,7 @@ display_output_one (display_t display, wchar_t chr)
 	case L'c':
 	  /* Clear screen and home cursor: <clear>.  */
 	  screen_fill (display, 0, 0,
-		       user->screen.width, user->screen.height,
+		       user->screen.width - 1, user->screen.height - 1,
 		       L' ', display->attr.current);
 	  user->cursor.col = user->cursor.row = 0;
 	  /* XXX Flag cursor change.  */
@@ -903,6 +1002,35 @@ display_output_one (display_t display, wchar_t chr)
     default:
       abort ();
     }
+
+  if (old_cursor_col != user->cursor.col || old_cursor_row != user->cursor.row)
+    display_notice_filechange (display, FILE_CHANGED_WRITE,
+			       offsetof (struct cons_display, cursor.col),
+			       (old_cursor_status == user->cursor.status
+			       ? offsetof (struct cons_display, cursor.row)
+			       : offsetof (struct cons_display, cursor.row))
+			       + sizeof (wchar_t) - 1);
+  else if (old_cursor_status != user->cursor.status)
+    display_notice_filechange (display, FILE_CHANGED_WRITE,
+			       offsetof (struct cons_display, cursor.status),
+			       offsetof (struct cons_display, cursor.status)
+			       + sizeof (wchar_t) - 1);
+  if (old_cur_line != user->screen.cur_line)
+    display_notice_filechange (display, FILE_CHANGED_WRITE,
+			       offsetof (struct cons_display, screen.cur_line),
+			       (old_scr_lines == user->screen.scr_lines
+				? offsetof (struct cons_display,
+					    screen.cur_line)
+				: offsetof (struct cons_display,
+					    screen.scr_lines))
+			       + sizeof (wchar_t) - 1);
+  else if (old_scr_lines != user->screen.scr_lines)
+    display_notice_filechange (display, FILE_CHANGED_WRITE,
+			       offsetof (struct cons_display,
+					 screen.scr_lines),
+			       offsetof (struct cons_display,
+					 screen.scr_lines)
+			       + sizeof (wchar_t) - 1);
 }
 
 /* Output LENGTH bytes starting from BUFFER in the system encoding.
@@ -996,6 +1124,8 @@ display_create (display_t *r_display, const char *encoding)
 void
 display_destroy (display_t display)
 {
+  if (display->filemod_reqs)
+    free_modreqs (display->filemod_reqs);
   output_deinit (&display->output);
   user_destroy (display);
   free (display);
diff --git a/console/display.h b/console/display.h
index c48aec99..303c42e2 100644
--- a/console/display.h
+++ b/console/display.h
@@ -60,6 +60,8 @@ mach_port_t display_get_filemap (display_t display, vm_prot_t prot);
 ssize_t display_read (display_t display, int nonblock, off_t off,
 		      char *data, size_t len);
 
+error_t display_notice_changes (display_t display, mach_port_t notify);
+
 /* Resume the output on the display DISPLAY.  */
 void display_start_output (display_t display);
 
diff --git a/console/ourfs_notify.defs b/console/ourfs_notify.defs
new file mode 100644
index 00000000..64127fe6
--- /dev/null
+++ b/console/ourfs_notify.defs
@@ -0,0 +1,5 @@
+/* Private specialized presentation of fs_notify.defs for diskfs library.  */
+
+#define routine simpleroutine
+#define USERPREFIX nowait_
+#include <hurd/fs_notify.defs>
-- 
cgit v1.2.3