bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

smcup and rmcup support for the console server


From: Marco Gerards
Subject: smcup and rmcup support for the console server
Date: 05 Aug 2003 23:54:58 +0200
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.2

Hi,

Here is a little patch so smcup and rmcup are supported in the console
server. I know this patch is far from perfect, perhaps I'm not even
doing the right thing.

A later version will support 3 options:
--rmcup=on
--rmcup=off
--rmcup=to-scrollback-buffer

I know that these argument names suck and I'd like to hear a good
alternative name. :)

Some short technical descriptions of these options:

rmcup=on

Works more or less the same as on xterm. Xterm really
switches to an alternative screen, this patch doesn't work that way. It
just backups the visible screen and cleans it. Because of this the
scrollback buffer still works.

There is one problem with this mode. Because I just backup the visible
screen and don't put any other restrictions on the screen (is this
possible and do we want this?). The "smcup application" can destroy
the scrollback buffer a bit as I have noticed. less does this for
example. (It can clear one screen of the scrollback buffer).

Perhaps I don't understand the console good enough to see why this
exactly happens. I know this can be prevented by backing up the whole
buffer instead of just the visible screen.

rmcup=off

Old behavior

rmcup=to-scrollback-buffer

This nice feature was a really good idea of Marcus. It does the same
as rmcup, but puts the alternate screen in the scrollback buffer
instead of overwriting it.

This has one advantage. When you use C-z a lot with emacs it fills up
you scrollbackbuffer really fast. :)

I hope someone will have a look at this patch and will comment on
it. I didn't put it on savannah yet because it is far from
perfect.

You can also help me by testing this patch for me! :)

Thanks,
Marco

2003-08-03  Marco Gerards  <metgerards@student.han.nl>

        * display.c (struct display): New member ALT_CURSOR and ALT_SCREEN.
        (screen_to_alternate): New function.
        (screen_from_alternate): Likewise.
        (handle_esc_bracket_right_angle_hl): Implement smcup and rmcup.
        * hurd.ti: Add capabilities smcup and rmcup.


Only in console: #display.#
Only in console: .#display.
Common subdirectories: /home/marco/src/hurdcvs/hurd/console/CVS and console/CVS
diff -up /home/marco/src/hurdcvs/hurd/console/display.c console/display.c
--- /home/marco/src/hurdcvs/hurd/console/display.c      2003-06-03 
23:19:00.000000000 +0200
+++ console/display.c   2003-08-05 19:32:33.000000000 +0200
@@ -184,6 +184,22 @@ struct display
 
   struct cons_display *user;
 
+  /* The backup of the screen and cursor position used for switching
+     to the alternate screen. Notice there is no real alternate
+     screen, the alternate screen created by backing up the current
+     screen and clearing it.  */
+  struct cursor alt_cursor;
+  struct
+  {
+    /* Width of screen matrix.  */
+    uint32_t width;
+    /* Number of lines in visible area following
+       (and including) CUR_LINE.  */
+    uint32_t height;
+    /* Is NULL when the alternate screen is not active.  */
+    conchar_t *_matrixp;
+  } alt_screen;
+
   /* The pager for the USER member.  */
   struct user_pager user_pager;
 
@@ -1075,6 +1091,115 @@ void limit_cursor (display_t display)
   /* XXX Flag cursor change.  */
 }
 
+/* Switch the screen on DISPLAY to the "alternate screen".  */
+static void
+screen_to_alternate (display_t display)
+{
+  struct cons_display *user = display->user;
+
+  off_t start = ((user->screen.cur_line % user->screen.lines))
+    * user->screen.width;
+  off_t end = (((user->screen.cur_line % user->screen.lines) 
+               + user->screen.height - 1)
+              * user->screen.width + user->screen.width - 1);
+  off_t size = (user->screen.width * user->screen.lines);
+
+  if (start >= size && end >= size)
+    {
+      start -= size;
+      end -= size;
+    }
+
+  /* Save the cursor position. XXX: Should the visibility be saved?  */
+  display->alt_cursor.saved_x = user->cursor.col;
+  display->alt_cursor.saved_y = user->cursor.row;
+
+  /* Save the screen, including its dimensions.  */
+  display->alt_screen.width = user->screen.width;
+  display->alt_screen.height = user->screen.height;
+
+  /* XXX: Only save the visible screen. Perhaps we should save the
+     complete buffer because the alternative screen can affect the
+     scrollback buffer. */
+  display->alt_screen._matrixp
+    = malloc (user->screen.width * user->screen.height * sizeof (conchar_t));
+
+  if (end < size)
+    memcpy (display->alt_screen._matrixp,
+           user->_matrix + start, (end - start + 1) * sizeof (conchar_t));
+  else
+    {
+      memcpy (display->alt_screen._matrixp, 
+             user->_matrix + start, (size - start) * sizeof (conchar_t));
+      memcpy (display->alt_screen._matrixp + size - start,
+             user->_matrix, (end - size) * sizeof (conchar_t));
+    }
+
+  /* Clear the "alternate screen".  */
+  screen_fill (display, 0, 0,
+              user->screen.width - 1, user->screen.height - 1,
+              L' ', display->attr.current);
+}
+
+/* The screen on DISPLAY is showing the alternate screen, switch back
+   to the regular screen.  */
+static void
+screen_from_alternate (display_t display)
+{
+  struct cons_display *user = display->user;
+
+  /* Keep the alternate screen in the scrollback buffer. XXX: This
+     should be made optional.  */
+  user->screen.cur_line += user->screen.height;
+
+  off_t start = ((user->screen.cur_line % user->screen.lines))
+    * user->screen.width;
+
+  off_t end = (((user->screen.cur_line % user->screen.lines) 
+               + user->screen.height - 1)
+              * user->screen.width + user->screen.width - 1);
+  off_t size = (user->screen.width * user->screen.lines);
+
+  if (start >= size && end >= size)
+    {
+      start -= size;
+      end -= size;
+    }
+
+  /* The screen has been resized while the alternate screen was
+     active, don't restore the old screen.  */
+  if (user->screen.width != display.alt_screen.width
+      || user->screen.height != display.alt_screen.height)
+    {
+      free (display->alt_screen._matrixp);
+      display->alt_screen._matrixp = 0;
+      return 0;
+    }
+  
+  if (end < size)
+    {
+      memcpy (user->_matrix + start, display->alt_screen._matrixp,
+             (end - start + 1) * sizeof (conchar_t));
+
+      display_record_filechange (display, start, end);
+    }
+  else
+    {
+      memcpy (user->_matrix + start, display->alt_screen._matrixp, 
+             (size - start) * sizeof (conchar_t));
+      memcpy (user->_matrix, display->alt_screen._matrixp + size - start,
+             (end - size) * sizeof (conchar_t));
+      display_record_filechange (display, start, end - size);
+    }
+
+  free (display->alt_screen._matrixp);
+  display->alt_screen._matrixp = 0;
+             
+  user->cursor.col = display->alt_cursor.saved_x;
+  user->cursor.row = display->alt_cursor.saved_y;
+  /* In case the screen was larger before:  */
+  limit_cursor (display);
+}
 
 static void
 linefeed (display_t display)
@@ -1434,6 +1559,21 @@ handle_esc_bracket_right_angle_hl (displ
       else
        display->attr.current.bold = 0;
       break;
+    case 2:
+      /* <smcup>, <rmcup>. Use this to safe and restore the screen.  */
+      if (flag) /* smcup.  */
+       {
+         /* Backup the screen.  */
+         if (display->alt_screen._matrixp == NULL)
+           screen_to_alternate (display);
+       }
+      else /* rmcup.  */
+       {
+         /* Restore the screen.  */
+         if (display->alt_screen._matrixp != NULL)
+           screen_from_alternate (display);
+       }
+      break;
     }
 }
 
diff -up /home/marco/src/hurdcvs/hurd/console/hurd.ti console/hurd.ti
--- /home/marco/src/hurdcvs/hurd/console/hurd.ti        2002-10-10 
14:26:04.000000000 +0200
+++ console/hurd.ti     2003-08-05 19:30:03.000000000 +0200
@@ -64,6 +64,8 @@ hurd|The GNU Hurd console server,
        ed=\E[J,
 # Clear to end (beginning) of line.
        el=\E[K, el1=\E[1K,
+# Switch to (from) alternate screen.
+       smcup=\E[>2h, rmcup=\E[>2l,
 
 # Insert one character (P1 characters).
 # <ich1> not included because we have insert mode.





reply via email to

[Prev in Thread] Current Thread [Next in Thread]