]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - ncurses/win32con/win_driver.c
ncurses 5.9 - patch 20140222
[ncurses.git] / ncurses / win32con / win_driver.c
index c214639cd4df29e8025646f9af44a276a54ee39b..c664d92387cc85a9608b7dd3dcbe37006c923cd3 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc.              *
+ * Copyright (c) 1998-2013,2014 Free Software Foundation, Inc.              *
  *                                                                          *
  * Permission is hereby granted, free of charge, to any person obtaining a  *
  * copy of this software and associated documentation files (the            *
 
 /****************************************************************************
  *  Author: Juergen Pfeifer                                                 *
- *                                                                          *
  ****************************************************************************/
 
 /*
  * TODO - GetMousePos(POINT * result) from ntconio.c
  * TODO - implement nodelay
+ * TODO - when $NCGDB is set, implement non-buffered output, like PDCurses
  */
 
 #include <curses.priv.h>
 #define CUR my_term.type.
 
-MODULE_ID("$Id: win_driver.c,v 1.10 2010/12/25 19:28:21 tom Exp $")
+MODULE_ID("$Id: win_driver.c,v 1.24 2014/02/23 01:23:29 tom Exp $")
 
 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
 
-#define AssertTCB() assert(TCB!=0 && TCB->magic==WINMAGIC)
-#define SetSP() assert(TCB->csp!=0); sp = TCB->csp
+#define EXP_OPTIMIZE 0
+
+#define okConsoleHandle(TCB) (TCB != 0 && !InvalidConsoleHandle(TCB->hdl))
+
+#define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC))
+#define SetSP()     assert(TCB->csp != 0); sp = TCB->csp; (void) sp
 
 #define GenMap(vKey,key) MAKELONG(key, vKey)
 
+#define AdjustY(p) ((p)->buffered ? 0 : (int) (p)->SBI.srWindow.Top)
+
 static const LONG keylist[] =
 {
     GenMap(VK_PRIOR, KEY_PPAGE),
@@ -69,9 +75,13 @@ static const LONG keylist[] =
 typedef struct props {
     CONSOLE_SCREEN_BUFFER_INFO SBI;
     bool progMode;
+    TERM_HANDLE lastOut;
     DWORD map[MAPSIZE];
     DWORD rmap[MAPSIZE];
     WORD pairs[NUMPAIRS];
+    bool buffered;
+    COORD origin;
+    CHAR_INFO *save_screen;
 } Properties;
 
 #define PropOf(TCB) ((Properties*)TCB->prop)
@@ -103,7 +113,7 @@ MapColor(bool fore, int color)
 }
 
 static WORD
-MapAttr(TERMINAL_CONTROL_BLOCK * TCB, WORD res, chtype ch)
+MapAttr(TERMINAL_CONTROL_BLOCK * TCB, WORD res, attr_t ch)
 {
     if (ch & A_COLOR) {
        int p;
@@ -135,8 +145,69 @@ MapAttr(TERMINAL_CONTROL_BLOCK * TCB, WORD res, chtype ch)
     return res;
 }
 
+#if USE_WIDEC_SUPPORT
+/*
+ * TODO: support surrogate pairs
+ * TODO: support combining characters
+ * TODO: support acsc
+ * TODO: check wcwidth of base character, fill if needed for double-width
+ * TODO: _nc_wacs should be part of sp.
+ */
+static BOOL
+con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit)
+{
+    int actual = 0;
+    CHAR_INFO ci[limit];
+    COORD loc, siz;
+    SMALL_RECT rec;
+    int i;
+    cchar_t ch;
+    SCREEN *sp;
+    Properties *p = PropOf(TCB);
+
+    AssertTCB();
+
+    SetSP();
+
+    for (i = actual = 0; i < limit; i++) {
+       ch = str[i];
+       if (isWidecExt(ch))
+           continue;
+       ci[actual].Char.UnicodeChar = CharOf(ch);
+       ci[actual].Attributes = MapAttr(TCB,
+                                       PropOf(TCB)->SBI.wAttributes,
+                                       AttrOf(ch));
+       if (AttrOf(ch) & A_ALTCHARSET) {
+           if (_nc_wacs) {
+               int which = CharOf(ch);
+               if (which > 0
+                   && which < ACS_LEN
+                   && CharOf(_nc_wacs[which]) != 0) {
+                   ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]);
+               } else {
+                   ci[actual].Char.UnicodeChar = ' ';
+               }
+           }
+       }
+       ++actual;
+    }
+
+    loc.X = (short) 0;
+    loc.Y = (short) 0;
+    siz.X = (short) actual;
+    siz.Y = 1;
+
+    rec.Left = (short) x;
+    rec.Top = (SHORT) (y + AdjustY(p));
+    rec.Right = (short) (x + limit - 1);
+    rec.Bottom = rec.Top;
+
+    return WriteConsoleOutputW(TCB->hdl, ci, siz, loc, &rec);
+}
+#define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n)
+#else
 static BOOL
-con_write(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
+con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
 {
     CHAR_INFO ci[n];
     COORD loc, siz;
@@ -147,9 +218,6 @@ con_write(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
 
     AssertTCB();
 
-    if (TCB == 0 || InvalidConsoleHandle(TCB->hdl))
-       return FALSE;
-
     SetSP();
 
     for (i = 0; i < n; i++) {
@@ -161,7 +229,7 @@ con_write(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
        if (ChAttrOf(ch) & A_ALTCHARSET) {
            if (sp->_acs_map)
                ci[i].Char.AsciiChar =
-                   ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
+               ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
        }
     }
 
@@ -177,55 +245,163 @@ con_write(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
 
     return WriteConsoleOutput(TCB->hdl, ci, siz, loc, &rec);
 }
+#define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n)
+#endif
+
+#if EXP_OPTIMIZE
+/*
+ * Comparing new/current screens, determine the last column-index for a change
+ * beginning on the given row,col position.  Unlike a serial terminal, there is
+ * no cost for "moving" the "cursor" on the line as we update it.
+ */
+static int
+find_end_of_change(SCREEN *sp, int row, int col)
+{
+    int result = col;
+    struct ldat *curdat = CurScreen(sp)->_line + row;
+    struct ldat *newdat = NewScreen(sp)->_line + row;
+
+    while (col <= newdat->lastchar) {
+#if USE_WIDEC_SUPPORT
+       if (isWidecExt(curdat->text[col]) || isWidecExt(newdat->text[col])) {
+           result = col;
+       } else if (memcmp(&curdat->text[col],
+                         &newdat->text[col],
+                         sizeof(curdat->text[0]))) {
+           result = col;
+       } else {
+           break;
+       }
+#else
+       if (curdat->text[col] != newdat->text[col]) {
+           result = col;
+       } else {
+           break;
+       }
+#endif
+       ++col;
+    }
+    return result;
+}
+
+/*
+ * Given a row,col position at the end of a change-chunk, look for the
+ * beginning of the next change-chunk.
+ */
+static int
+find_next_change(SCREEN *sp, int row, int col)
+{
+    struct ldat *curdat = CurScreen(sp)->_line + row;
+    struct ldat *newdat = NewScreen(sp)->_line + row;
+    int result = newdat->lastchar + 1;
+
+    while (++col <= newdat->lastchar) {
+#if USE_WIDEC_SUPPORT
+       if (isWidecExt(curdat->text[col]) != isWidecExt(newdat->text[col])) {
+           result = col;
+           break;
+       } else if (memcmp(&curdat->text[col],
+                         &newdat->text[col],
+                         sizeof(curdat->text[0]))) {
+           result = col;
+           break;
+       }
+#else
+       if (curdat->text[col] != newdat->text[col]) {
+           result = col;
+           break;
+       }
+#endif
+    }
+    return result;
+}
+
+#define EndChange(first) \
+       find_end_of_change(sp, y, first)
+#define NextChange(last) \
+       find_next_change(sp, y, last)
+
+#endif /* EXP_OPTIMIZE */
 
 #define MARK_NOCHANGE(win,row) \
                win->_line[row].firstchar = _NOCHANGE; \
                win->_line[row].lastchar  = _NOCHANGE
 
+static void
+selectActiveHandle(TERMINAL_CONTROL_BLOCK * TCB)
+{
+    if (PropOf(TCB)->lastOut != TCB->hdl) {
+       PropOf(TCB)->lastOut = TCB->hdl;
+       SetConsoleActiveScreenBuffer(PropOf(TCB)->lastOut);
+    }
+}
+
 static int
 drv_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
 {
+    int result = ERR;
     int y, nonempty, n, x0, x1, Width, Height;
     SCREEN *sp;
 
     AssertTCB();
     SetSP();
 
-    Width = screen_columns(sp);
-    Height = screen_lines(sp);
-    nonempty = min(Height, NewScreen(sp)->_maxy + 1);
+    T((T_CALLED("win32con::drv_doupdate(%p)"), TCB));
+    if (okConsoleHandle(TCB)) {
 
-    if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
-       int x;
-       chtype empty[Width];
+       Width = screen_columns(sp);
+       Height = screen_lines(sp);
+       nonempty = min(Height, NewScreen(sp)->_maxy + 1);
 
-       for (x = 0; x < Width; x++)
-           empty[x] = ' ';
+       if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
+           int x;
+#if USE_WIDEC_SUPPORT
+           cchar_t empty[Width];
+           wchar_t blank[2] =
+           {
+               L' ', L'\0'
+           };
 
-       for (y = 0; y < nonempty; y++) {
-           con_write(TCB, y, 0, empty, Width);
-           memcpy(empty,
-                  CurScreen(sp)->_line[y].text,
-                  Width * sizeof(chtype));
+           for (x = 0; x < Width; x++)
+               setcchar(&empty[x], blank, 0, 0, 0);
+#else
+           chtype empty[Width];
+
+           for (x = 0; x < Width; x++)
+               empty[x] = ' ';
+#endif
+
+           for (y = 0; y < nonempty; y++) {
+               con_write(TCB, y, 0, empty, Width);
+               memcpy(empty,
+                      CurScreen(sp)->_line[y].text,
+                      (size_t) Width * sizeof(empty[0]));
+           }
+           CurScreen(sp)->_clear = FALSE;
+           NewScreen(sp)->_clear = FALSE;
+           touchwin(NewScreen(sp));
        }
-       CurScreen(sp)->_clear = FALSE;
-       NewScreen(sp)->_clear = FALSE;
-       touchwin(NewScreen(sp));
-    }
 
-    for (y = 0; y < nonempty; y++) {
-       x0 = NewScreen(sp)->_line[y].firstchar;
-       if (x0 != _NOCHANGE) {
-           x1 = NewScreen(sp)->_line[y].lastchar;
-           n = x1 - x0 + 1;
-           if (n > 0) {
-               memcpy(CurScreen(sp)->_line[y].text + x0,
-                      NewScreen(sp)->_line[y].text + x0,
-                      n * sizeof(chtype));
-               con_write(TCB,
-                         y,
-                         x0,
-                         ((chtype *) CurScreen(sp)->_line[y].text) + x0, n);
+       for (y = 0; y < nonempty; y++) {
+           x0 = NewScreen(sp)->_line[y].firstchar;
+           if (x0 != _NOCHANGE) {
+#if EXP_OPTIMIZE
+               int x2;
+               int limit = NewScreen(sp)->_line[y].lastchar;
+               while ((x1 = EndChange(x0)) <= limit) {
+                   while ((x2 = NextChange(x1)) <= limit && x2 <= (x1 + 2)) {
+                       x1 = x2;
+                   }
+                   n = x1 - x0 + 1;
+                   memcpy(&CurScreen(sp)->_line[y].text[x0],
+                          &NewScreen(sp)->_line[y].text[x0],
+                          n * sizeof(CurScreen(sp)->_line[y].text[x0]));
+                   con_write(TCB,
+                             y,
+                             x0,
+                             &CurScreen(sp)->_line[y].text[x0], n);
+                   x0 = NextChange(x1);
+               }
 
                /* mark line changed successfully */
                if (y <= NewScreen(sp)->_maxy) {
@@ -234,26 +410,50 @@ drv_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
                if (y <= CurScreen(sp)->_maxy) {
                    MARK_NOCHANGE(CurScreen(sp), y);
                }
+#else
+               x1 = NewScreen(sp)->_line[y].lastchar;
+               n = x1 - x0 + 1;
+               if (n > 0) {
+                   memcpy(&CurScreen(sp)->_line[y].text[x0],
+                          &NewScreen(sp)->_line[y].text[x0],
+                          (size_t) n * sizeof(CurScreen(sp)->_line[y].text[x0]));
+                   con_write(TCB,
+                             y,
+                             x0,
+                             &CurScreen(sp)->_line[y].text[x0], n);
+
+                   /* mark line changed successfully */
+                   if (y <= NewScreen(sp)->_maxy) {
+                       MARK_NOCHANGE(NewScreen(sp), y);
+                   }
+                   if (y <= CurScreen(sp)->_maxy) {
+                       MARK_NOCHANGE(CurScreen(sp), y);
+                   }
+               }
+#endif
            }
        }
-    }
 
-    /* put everything back in sync */
-    for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
-       MARK_NOCHANGE(NewScreen(sp), y);
-    }
-    for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
-       MARK_NOCHANGE(CurScreen(sp), y);
-    }
+       /* put everything back in sync */
+       for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
+           MARK_NOCHANGE(NewScreen(sp), y);
+       }
+       for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
+           MARK_NOCHANGE(CurScreen(sp), y);
+       }
 
-    if (!NewScreen(sp)->_leaveok) {
-       CurScreen(sp)->_curx = NewScreen(sp)->_curx;
-       CurScreen(sp)->_cury = NewScreen(sp)->_cury;
+       if (!NewScreen(sp)->_leaveok) {
+           CurScreen(sp)->_curx = NewScreen(sp)->_curx;
+           CurScreen(sp)->_cury = NewScreen(sp)->_cury;
 
-       TCB->drv->hwcur(TCB, 0, 0, CurScreen(sp)->_cury, CurScreen(sp)->_curx);
+           TCB->drv->hwcur(TCB,
+                           0, 0,
+                           CurScreen(sp)->_cury, CurScreen(sp)->_curx);
+       }
+       selectActiveHandle(TCB);
+       result = OK;
     }
-    SetConsoleActiveScreenBuffer(TCB->hdl);
-    return OK;
+    returnCode(result);
 }
 
 static bool
@@ -269,14 +469,14 @@ drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
     assert(tname != 0);
 
     TCB->magic = WINMAGIC;
-    if (*tname == 0 || *tname == 0) {
+    if (*tname == 0 || *tname == 0 || *tname == '#') {
        code = TRUE;
     } else {
        TERMINAL my_term;
        int status;
 
        code = FALSE;
-#if (USE_DATABASE || USE_TERMCAP)
+#if (NCURSES_USE_DATABASE || NCURSES_USE_TERMCAP)
        status = _nc_setup_tinfo(tname, &my_term.type);
 #else
        status = TGETENT_NO;
@@ -299,7 +499,7 @@ drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
 
     if (code) {
        if ((TCB->term.type.Booleans) == 0) {
-           _nc_init_entry(&(TCB->term.type));
+           _nc_init_termtype(&(TCB->term.type));
        }
     }
 
@@ -308,7 +508,7 @@ drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
 
 static int
 drv_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
-               bool beepFlag GCC_UNUSED)
+               int beepFlag GCC_UNUSED)
 {
     SCREEN *sp;
     int res = ERR;
@@ -346,19 +546,55 @@ drv_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
     return (code);
 }
 
+static bool
+get_SBI(TERMINAL_CONTROL_BLOCK * TCB)
+{
+    bool rc = FALSE;
+    Properties *p = PropOf(TCB);
+    if (GetConsoleScreenBufferInfo(TCB->hdl, &(p->SBI))) {
+       T(("GetConsoleScreenBufferInfo"));
+       T(("... buffer(X:%d Y:%d)",
+          p->SBI.dwSize.X,
+          p->SBI.dwSize.Y));
+       T(("... window(X:%d Y:%d)",
+          p->SBI.dwMaximumWindowSize.X,
+          p->SBI.dwMaximumWindowSize.Y));
+       T(("... cursor(X:%d Y:%d)",
+          p->SBI.dwCursorPosition.X,
+          p->SBI.dwCursorPosition.Y));
+       T(("... display(Top:%d Bottom:%d Left:%d Right:%d)",
+          p->SBI.srWindow.Top,
+          p->SBI.srWindow.Bottom,
+          p->SBI.srWindow.Left,
+          p->SBI.srWindow.Right));
+       if (p->buffered) {
+           p->origin.X = 0;
+           p->origin.Y = 0;
+       } else {
+           p->origin.X = p->SBI.srWindow.Left;
+           p->origin.Y = p->SBI.srWindow.Top;
+       }
+       rc = TRUE;
+    } else {
+       T(("GetConsoleScreenBufferInfo ERR"));
+    }
+    return rc;
+}
+
 static void
 drv_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
-            bool fore,
+            int fore,
             int color,
             int (*outc) (SCREEN *, int) GCC_UNUSED)
 {
     AssertTCB();
 
-    if (TCB && !InvalidConsoleHandle(TCB->hdl)) {
+    if (okConsoleHandle(TCB) &&
+       PropOf(TCB) != 0) {
        WORD a = MapColor(fore, color);
-       a = ((PropOf(TCB)->SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f)) | a;
+       a |= (WORD) ((PropOf(TCB)->SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
        SetConsoleTextAttribute(TCB->hdl, a);
-       GetConsoleScreenBufferInfo(TCB->hdl, &(PropOf(TCB)->SBI));
+       get_SBI(TCB);
     }
 }
 
@@ -368,10 +604,10 @@ drv_rescol(TERMINAL_CONTROL_BLOCK * TCB)
     bool res = FALSE;
 
     AssertTCB();
-    if (TCB && !InvalidConsoleHandle(TCB->hdl)) {
+    if (okConsoleHandle(TCB)) {
        WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
        SetConsoleTextAttribute(TCB->hdl, a);
-       GetConsoleScreenBufferInfo(TCB->hdl, &(PropOf(TCB)->SBI));
+       get_SBI(TCB);
        res = TRUE;
     }
     return res;
@@ -392,14 +628,28 @@ drv_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
 static int
 drv_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
 {
+    int result = ERR;
+
     AssertTCB();
 
-    if (TCB == NULL || Lines == NULL || Cols == NULL || InvalidConsoleHandle(TCB->hdl))
-       return ERR;
+    T((T_CALLED("win32con::drv_size(%p)"), TCB));
 
-    *Lines = (int) (PropOf(TCB)->SBI.dwSize.Y);
-    *Cols = (int) (PropOf(TCB)->SBI.dwSize.X);
-    return OK;
+    if (okConsoleHandle(TCB) &&
+       PropOf(TCB) != 0 &&
+       Lines != NULL &&
+       Cols != NULL) {
+       if (PropOf(TCB)->buffered) {
+           *Lines = (int) (PropOf(TCB)->SBI.dwSize.Y);
+           *Cols = (int) (PropOf(TCB)->SBI.dwSize.X);
+       } else {
+           *Lines = (int) (PropOf(TCB)->SBI.srWindow.Bottom + 1 -
+                           PropOf(TCB)->SBI.srWindow.Top);
+           *Cols = (int) (PropOf(TCB)->SBI.srWindow.Right + 1 -
+                          PropOf(TCB)->SBI.srWindow.Left);
+       }
+       result = OK;
+    }
+    returnCode(result);
 }
 
 static int
@@ -412,7 +662,7 @@ drv_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
 }
 
 static int
-drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, bool setFlag, TTY * buf)
+drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
 {
     DWORD dwFlag = 0;
     tcflag_t iflag;
@@ -432,17 +682,17 @@ drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, bool setFlag, TTY * buf)
        if (lflag & ICANON)
            dwFlag |= ENABLE_LINE_INPUT;
        else
-           dwFlag &= ~ENABLE_LINE_INPUT;
+           dwFlag &= (DWORD) (~ENABLE_LINE_INPUT);
 
        if (lflag & ECHO)
            dwFlag |= ENABLE_ECHO_INPUT;
        else
-           dwFlag &= ~ENABLE_ECHO_INPUT;
+           dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT);
 
        if (iflag & BRKINT)
            dwFlag |= ENABLE_PROCESSED_INPUT;
        else
-           dwFlag &= ~ENABLE_PROCESSED_INPUT;
+           dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT);
 
        dwFlag |= ENABLE_MOUSE_INPUT;
 
@@ -458,17 +708,17 @@ drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, bool setFlag, TTY * buf)
        if (dwFlag & ENABLE_LINE_INPUT)
            lflag |= ICANON;
        else
-           lflag &= ~ICANON;
+           lflag &= (tcflag_t) (~ICANON);
 
        if (dwFlag & ENABLE_ECHO_INPUT)
            lflag |= ECHO;
        else
-           lflag &= ~ECHO;
+           lflag &= (tcflag_t) (~ECHO);
 
        if (dwFlag & ENABLE_PROCESSED_INPUT)
            iflag |= BRKINT;
        else
-           iflag &= ~BRKINT;
+           iflag &= (tcflag_t) (~BRKINT);
 
        TCB->term.Nttyb.c_iflag = iflag;
        TCB->term.Nttyb.c_lflag = lflag;
@@ -479,7 +729,7 @@ drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, bool setFlag, TTY * buf)
 }
 
 static int
-drv_mode(TERMINAL_CONTROL_BLOCK * TCB, bool progFlag, bool defFlag)
+drv_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
 {
     SCREEN *sp;
     TERMINAL *_term = (TERMINAL *) TCB;
@@ -489,12 +739,13 @@ drv_mode(TERMINAL_CONTROL_BLOCK * TCB, bool progFlag, bool defFlag)
     sp = TCB->csp;
 
     PropOf(TCB)->progMode = progFlag;
-    SetConsoleActiveScreenBuffer(progFlag ? TCB->hdl : TCB->out);
+    PropOf(TCB)->lastOut = progFlag ? TCB->hdl : TCB->out;
+    SetConsoleActiveScreenBuffer(PropOf(TCB)->lastOut);
 
     if (progFlag) /* prog mode */  {
        if (defFlag) {
            if ((drv_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
-               _term->Nttyb.c_oflag &= ~OFLAGS_TABS;
+               _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS);
                code = OK;
            }
        } else {
@@ -593,6 +844,92 @@ drv_release(TERMINAL_CONTROL_BLOCK * TCB)
     returnVoid;
 }
 
+/*
+ * Attempt to save the screen contents.  PDCurses does this if
+ * PDC_RESTORE_SCREEN is set, giving the same visual appearance on restoration
+ * as if the library had allocated a console buffer.
+ */
+static bool
+save_original_screen(TERMINAL_CONTROL_BLOCK * TCB)
+{
+    bool result = FALSE;
+    Properties *p = PropOf(TCB);
+    COORD bufferSize;
+    COORD bufferCoord;
+    SMALL_RECT readRegion;
+    size_t want;
+
+    bufferSize.X = p->SBI.dwSize.X;
+    bufferSize.Y = p->SBI.dwSize.Y;
+    want = (size_t) (bufferSize.X * bufferSize.Y);
+
+    if ((p->save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
+       bufferCoord.X = bufferCoord.Y = 0;
+
+       readRegion.Top = 0;
+       readRegion.Left = 0;
+       readRegion.Bottom = (SHORT) (bufferSize.Y - 1);
+       readRegion.Right = (SHORT) (bufferSize.X - 1);
+
+       T(("... reading console buffer %dx%d into %d,%d - %d,%d at %d,%d",
+          bufferSize.Y, bufferSize.X,
+          readRegion.Top,
+          readRegion.Left,
+          readRegion.Bottom,
+          readRegion.Right,
+          bufferCoord.Y,
+          bufferCoord.X));
+
+       if (ReadConsoleOutput(TCB->hdl,
+                             p->save_screen,
+                             bufferSize,
+                             bufferCoord,
+                             &readRegion)) {
+           result = TRUE;
+       } else {
+           T((" error %#lx", (unsigned long) GetLastError()));
+           FreeAndNull(p->save_screen);
+
+           bufferSize.X = (SHORT) (p->SBI.srWindow.Right
+                                   - p->SBI.srWindow.Left + 1);
+           bufferSize.Y = (SHORT) (p->SBI.srWindow.Bottom
+                                   - p->SBI.srWindow.Top + 1);
+           want = (size_t) (bufferSize.X * bufferSize.Y);
+
+           if ((p->save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
+               bufferCoord.X = bufferCoord.Y = 0;
+
+               readRegion.Top = p->SBI.srWindow.Top;
+               readRegion.Left = p->SBI.srWindow.Left;
+               readRegion.Bottom = p->SBI.srWindow.Bottom;
+               readRegion.Right = p->SBI.srWindow.Right;
+
+               T(("... reading console window %dx%d into %d,%d - %d,%d at %d,%d",
+                  bufferSize.Y, bufferSize.X,
+                  readRegion.Top,
+                  readRegion.Left,
+                  readRegion.Bottom,
+                  readRegion.Right,
+                  bufferCoord.Y,
+                  bufferCoord.X));
+
+               if (ReadConsoleOutput(TCB->hdl,
+                                     p->save_screen,
+                                     bufferSize,
+                                     bufferCoord,
+                                     &readRegion)) {
+                   result = TRUE;
+               } else {
+                   T((" error %#lx", (unsigned long) GetLastError()));
+               }
+           }
+       }
+    }
+
+    T(("... save original screen contents %s", result ? "ok" : "err"));
+    return result;
+}
+
 static void
 drv_init(TERMINAL_CONTROL_BLOCK * TCB)
 {
@@ -606,6 +943,7 @@ drv_init(TERMINAL_CONTROL_BLOCK * TCB)
        BOOL b = AllocConsole();
        WORD a;
        int i;
+       bool buffered = TRUE;
 
        if (!b)
            b = AttachConsole(ATTACH_PARENT_PROCESS);
@@ -613,18 +951,31 @@ drv_init(TERMINAL_CONTROL_BLOCK * TCB)
        TCB->inp = GetStdHandle(STD_INPUT_HANDLE);
        TCB->out = GetStdHandle(STD_OUTPUT_HANDLE);
 
-       if (getenv("NCGDB"))
+       if (getenv("NCGDB")) {
            TCB->hdl = TCB->out;
-       else
+           buffered = FALSE;
+       } else {
            TCB->hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
                                                 0,
                                                 NULL,
                                                 CONSOLE_TEXTMODE_BUFFER,
                                                 NULL);
+       }
 
-       if (!InvalidConsoleHandle(TCB->hdl)) {
-           TCB->prop = typeCalloc(Properties, 1);
-           GetConsoleScreenBufferInfo(TCB->hdl, &(PropOf(TCB)->SBI));
+       if (InvalidConsoleHandle(TCB->hdl)) {
+           returnVoid;
+       } else if ((TCB->prop = typeCalloc(Properties, 1)) != 0) {
+           PropOf(TCB)->buffered = buffered;
+           if (!get_SBI(TCB)) {
+               FreeAndNull(TCB->prop);         /* force error in drv_size */
+               returnVoid;
+           }
+           if (!buffered) {
+               if (!save_original_screen(TCB)) {
+                   FreeAndNull(TCB->prop);     /* force error in drv_size */
+                   returnVoid;
+               }
+           }
        }
 
        TCB->info.initcolor = TRUE;
@@ -642,7 +993,7 @@ drv_init(TERMINAL_CONTROL_BLOCK * TCB)
 
        if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
            T(("mouse has %ld buttons", num_buttons));
-           TCB->info.numbuttons = num_buttons;
+           TCB->info.numbuttons = (int) num_buttons;
        } else {
            TCB->info.numbuttons = 1;
        }
@@ -651,7 +1002,7 @@ drv_init(TERMINAL_CONTROL_BLOCK * TCB)
 
        for (i = 0; i < (N_INI + FKEYS); i++) {
            if (i < N_INI)
-               PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] = keylist[i];
+               PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] = (DWORD) keylist[i];
            else
                PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] =
                    GenMap((VK_F1 + (i - N_INI)), (KEY_F(1) + (i - N_INI)));
@@ -674,9 +1025,9 @@ drv_init(TERMINAL_CONTROL_BLOCK * TCB)
 
 static void
 drv_initpair(TERMINAL_CONTROL_BLOCK * TCB,
-            short pair,
-            short f,
-            short b)
+            int pair,
+            int f,
+            int b)
 {
     SCREEN *sp;
 
@@ -691,10 +1042,10 @@ drv_initpair(TERMINAL_CONTROL_BLOCK * TCB,
 
 static void
 drv_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
-             short color GCC_UNUSED,
-             short r GCC_UNUSED,
-             short g GCC_UNUSED,
-             short b GCC_UNUSED)
+             int color GCC_UNUSED,
+             int r GCC_UNUSED,
+             int g GCC_UNUSED,
+             int b GCC_UNUSED)
 {
     SCREEN *sp;
 
@@ -704,9 +1055,9 @@ drv_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
 
 static void
 drv_do_color(TERMINAL_CONTROL_BLOCK * TCB,
-            short old_pair GCC_UNUSED,
-            short pair GCC_UNUSED,
-            bool reverse GCC_UNUSED,
+            int old_pair GCC_UNUSED,
+            int pair GCC_UNUSED,
+            int reverse GCC_UNUSED,
             int (*outc) (SCREEN *, int) GCC_UNUSED
 )
 {
@@ -755,10 +1106,11 @@ drv_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
          int y, int x)
 {
     int ret = ERR;
-    if (TCB && !InvalidConsoleHandle(TCB->hdl)) {
+    if (okConsoleHandle(TCB)) {
+       Properties *p = PropOf(TCB);
        COORD loc;
        loc.X = (short) x;
-       loc.Y = (short) y;
+       loc.Y = (short) (y + AdjustY(p));
        SetConsoleCursorPosition(TCB->hdl, loc);
        ret = OK;
     }
@@ -778,7 +1130,7 @@ drv_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
 
 static void
 drv_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
-                bool OnFlag GCC_UNUSED)
+                int OnFlag GCC_UNUSED)
 {
     SCREEN *sp;
 
@@ -844,7 +1196,7 @@ drv_initacs(TERMINAL_CONTROL_BLOCK * TCB,
     SetSP();
 
     for (n = 0; n < SIZEOF(table); ++n) {
-       real_map[table[n].acs_code] = table[n].use_code | A_ALTCHARSET;
+       real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET;
        if (sp != 0)
            sp->_screen_acs_map[table[n].acs_code] = TRUE;
     }
@@ -931,7 +1283,7 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
     SCREEN *sp;
     INPUT_RECORD inp_rec;
     BOOL b;
-    DWORD nRead = 0, rc = -1;
+    DWORD nRead = 0, rc = (DWORD) (-1);
     int code = 0;
     FILETIME fstart;
     FILETIME fend;
@@ -953,7 +1305,7 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
 
     while (true) {
        GetSystemTimeAsFileTime(&fstart);
-       rc = WaitForSingleObject(TCB->inp, milliseconds);
+       rc = WaitForSingleObject(TCB->inp, (DWORD) milliseconds);
        GetSystemTimeAsFileTime(&fend);
        diff = (int) tdiff(fstart, fend);
        milliseconds = Adjust(milliseconds, diff);
@@ -999,8 +1351,7 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
                            }
                            continue;
                        default:
-                           SetConsoleActiveScreenBuffer(!PropOf(TCB)->progMode ?
-                                                        TCB->hdl : TCB->out);
+                           selectActiveHandle(TCB);
                            continue;
                        }
                    }
@@ -1046,23 +1397,26 @@ handle_mouse(TERMINAL_CONTROL_BLOCK * TCB, MOUSE_EVENT_RECORD mer)
      * FIXME: implement continuous event-tracking.
      */
     if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) {
+       Properties *p = PropOf(TCB);
 
        memset(&work, 0, sizeof(work));
 
        if (sp->_drv_mouse_new_buttons) {
 
-           work.bstate |= decode_mouse(TCB, sp->_drv_mouse_new_buttons);
+           work.bstate |= (mmask_t) decode_mouse(TCB, sp->_drv_mouse_new_buttons);
 
        } else {
 
            /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
-           work.bstate |= (decode_mouse(TCB, sp->_drv_mouse_old_buttons) >> 1);
+           work.bstate |= (mmask_t) (decode_mouse(TCB,
+                                                  sp->_drv_mouse_old_buttons)
+                                     >> 1);
 
            result = TRUE;
        }
 
        work.x = mer.dwMousePosition.X;
-       work.y = mer.dwMousePosition.Y;
+       work.y = mer.dwMousePosition.Y - AdjustY(p);
 
        sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
        sp->_drv_mouse_tail += 1;
@@ -1080,7 +1434,6 @@ drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
     BOOL b;
     DWORD nRead;
     WORD vk;
-    WORD sc;
 
     AssertTCB();
     assert(buf);
@@ -1096,7 +1449,6 @@ drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
                    continue;
                *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar;
                vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
-               sc = inp_rec.Event.KeyEvent.wVirtualScanCode;
                if (*buf == 0) {
                    if (sp->_keypad_on) {
                        *buf = MapKey(TCB, vk);
@@ -1124,8 +1476,9 @@ drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
 static int
 drv_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
 {
-    Sleep(ms);
-    return OK;
+    T((T_CALLED("win32con::drv_nap(%p, %d)"), TCB, ms));
+    Sleep((DWORD) ms);
+    returnCode(OK);
 }
 
 static bool
@@ -1142,6 +1495,7 @@ drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int keycode)
 
     AssertTCB();
 
+    T((T_CALLED("win32con::drv_kyExist(%p, %d)"), TCB, keycode));
     res = bsearch(&key,
                  PropOf(TCB)->rmap,
                  (size_t) (N_INI + FKEYS),
@@ -1153,11 +1507,11 @@ drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int keycode)
        if (!(nKey & 0x8000))
            found = TRUE;
     }
-    return found;
+    returnCode(found);
 }
 
 static int
-drv_kpad(TERMINAL_CONTROL_BLOCK * TCB, bool flag GCC_UNUSED)
+drv_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
 {
     SCREEN *sp;
     int code = ERR;
@@ -1165,14 +1519,15 @@ drv_kpad(TERMINAL_CONTROL_BLOCK * TCB, bool flag GCC_UNUSED)
     AssertTCB();
     sp = TCB->csp;
 
+    T((T_CALLED("win32con::drv_kpad(%p, %d)"), TCB, flag));
     if (sp) {
        code = OK;
     }
-    return code;
+    returnCode(code);
 }
 
 static int
-drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, bool flag)
+drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, int flag)
 {
     int code = ERR;
     SCREEN *sp;
@@ -1184,6 +1539,7 @@ drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, bool flag)
     AssertTCB();
     SetSP();
 
+    T((T_CALLED("win32con::drv_keyok(%p, %d, %d)"), TCB, keycode, flag));
     if (sp) {
        res = bsearch(&key,
                      PropOf(TCB)->rmap,
@@ -1199,7 +1555,7 @@ drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, bool flag)
            *(LONG *) res = GenMap(vKey, nKey);
        }
     }
-    return code;
+    returnCode(code);
 }
 
 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {