Use a pad for storing the old screen during resize.
authorTimo Korvola <tkorvola@iki.fi>
Sat, 17 Feb 2018 18:36:21 +0000 (20:36 +0200)
committerTimo Korvola <tkorvola@iki.fi>
Sat, 17 Feb 2018 18:36:21 +0000 (20:36 +0200)
Why bother reinventing the wheel when curses does the job?

#42: Handle terminal resizing

src/curses/ux_screen.c

index a469f359d13dd7e7854a3091e14a847e0b692001..5460cc278ec484c66ccee556cdf889801e07b1ed 100644 (file)
@@ -37,6 +37,8 @@ extern void resize_screen(void);
 extern void restart_header(void);
 extern void restart_screen(void);
 
+static WINDOW *saved_screen = NULL;
+
 /*
  * os_erase_area
  *
@@ -136,61 +138,6 @@ void os_scroll_area (int top, int left, int bottom, int right, int units)
 }/* os_scroll_area */
 
 
-/*
- * Copy the screen into a buffer.  The buffer must be at least
- * cols * lines + 1 elements long and will contain the top left part of
- * the screen with the given dimensions.  Line n on the screen will start
- * at position col * n in the array.
- *
- * Reading stops on error, typically if the screen has fewer lines than
- * requested.  If n lines were successfully read, a zero is written at
- * position cols * n of the array (hence the size requirement).  If the
- * screen has fewer columns than requested, lines are read up to the last
- * column.  They may or may not be terminated by zero - it depends on
- * the curses implementation.
- *
- * The cursor position is affected.  The number of successfully read lines
- * is returned.
- */
-static int save_screen(int lines, int cols, chtype *buf)
-{
-    int li;
-    for (li = 0; li < lines; ++li)
-        if (ERR == mvinchnstr(li, 0, buf + li * cols, cols))
-            break;
-    buf[li * cols] = 0;
-    return li;
-}
-
-
-/*
- * Restore the screen from a buffer.  This is the inverse of save_screen.
- * The buffer must be at least cols * lines elements long.  See save_screen
- * about the layout.
- *
- * The screen is cleared first.  Areas are left blank if the buffer has
- * fewer columns or lines than the screen.  If the buffer has more columns
- * or lines than the screen, the leftmost columns and topmost lines are
- * printed, as much as will fit.  (This is probably what you want for
- * columns but not for lines, so add an appropriate offset to buf.)
- *
- * Writing stops early if a line in buf starts with zero or if there is an
- * error.  The cursor position is affected.  Returns the number of successfully
- * written lines.
- */
-static int restore_screen(int lines, int cols, const chtype *buf)
-{
-    int li, n = MIN(lines, LINES);
-    clear();
-    for (li = 0; li < n; ++li) {
-        const chtype *p = buf + li * cols;
-        if (!*p || ERR == mvaddchnstr(li, 0, p, cols))
-            break;
-    }
-    return li;
-}
-
-
 /*
  * unix_resize_display
  *
@@ -199,14 +146,15 @@ static int restore_screen(int lines, int cols, const chtype *buf)
  */
 void unix_resize_display(void)
 {
-    int x, y,
+    int x, y, start = 0,
         lines = h_screen_rows, cols = h_screen_cols;
-    chtype
-        *const buf = malloc(sizeof(chtype) * (cols * lines + 1)),
-        *pos = buf;
 
+    if ((saved_screen = newpad(lines, cols))
+        && overwrite(stdscr, saved_screen) == ERR) {
+        delwin(saved_screen);
+        saved_screen = NULL;
+    }
     getyx(stdscr, y, x);
-    lines = save_screen(lines, cols, buf);
 
     endwin();
     refresh();
@@ -215,16 +163,19 @@ void unix_resize_display(void)
         lines = h_screen_rows;
         if (y >= h_screen_rows) {
             /* Lose some topmost lines to keep the cursor on screen. */
-            int lost = y + 1 - h_screen_rows;
+            start = y + 1 - h_screen_rows;
             y = h_screen_rows - 1;
-            pos += cols * lost;
         }
     }
+    if (cols > h_screen_cols)
+        cols = h_screen_cols;
     if (x >= h_screen_cols)
         x = h_screen_cols - 1;
-    restore_screen(lines, cols, pos);
-    free(buf);
+    if (saved_screen)
+        copywin(saved_screen, stdscr, start, 0, 0, 0,
+                lines - 1, cols - 1, FALSE);
     move(y, x);
+    refresh();
 
     /* Notify the game that the display needs refreshing */
     if (h_version == V6)
@@ -234,4 +185,8 @@ void unix_resize_display(void)
        resize_screen();
        restart_header();
     }
+    if (saved_screen) {
+        delwin(saved_screen);
+        saved_screen = NULL;
+    }
 }/* unix_redraw_display */