]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - ncurses/win32con/win_driver.c
ncurses 5.9 - patch 20130105
[ncurses.git] / ncurses / win32con / win_driver.c
index 2b159b18316de98df9c7415c3c05b39d6413a65e..9b7a752ecc411a5f3d1eafd50dacdcde19775e30 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc.              *
+ * Copyright (c) 1998-2012,2013 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            *
@@ -28,7 +28,6 @@
 
 /****************************************************************************
  *  Author: Juergen Pfeifer                                                 *
- *                                                                          *
  ****************************************************************************/
 
 /*
  */
 
 #include <curses.priv.h>
+#define CUR my_term.type.
 
-MODULE_ID("$Id: win_driver.c,v 1.8 2010/04/10 19:42:47 tom Exp $")
+MODULE_ID("$Id: win_driver.c,v 1.16 2013/01/05 23:16:54 tom Exp $")
 
 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
 
+#define EXP_OPTIMIZE 0
+
 #define AssertTCB() assert(TCB!=0 && TCB->magic==WINMAGIC)
-#define SetSP() assert(TCB->csp!=0); sp = TCB->csp
+#define SetSP() assert(TCB->csp!=0); sp = TCB->csp; (void) sp
 
 #define GenMap(vKey,key) MAKELONG(key, vKey)
 
@@ -102,7 +104,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;
@@ -134,8 +136,71 @@ 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;
+
+    AssertTCB();
+
+    if (TCB == 0 || InvalidConsoleHandle(TCB->hdl))
+       return FALSE;
+
+    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;
+    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;
@@ -176,6 +241,83 @@ 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; \
@@ -196,16 +338,27 @@ drv_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
 
     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 (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,
-                  Width * sizeof(chtype));
+                  Width * sizeof(empty[0]));
        }
        CurScreen(sp)->_clear = FALSE;
        NewScreen(sp)->_clear = FALSE;
@@ -215,16 +368,42 @@ drv_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
     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) {
+               MARK_NOCHANGE(NewScreen(sp), y);
+           }
+           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,
-                      n * sizeof(chtype));
+               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,
-                         ((chtype *) CurScreen(sp)->_line[y].text) + x0, n);
+                         &CurScreen(sp)->_line[y].text[x0], n);
 
                /* mark line changed successfully */
                if (y <= NewScreen(sp)->_maxy) {
@@ -234,6 +413,7 @@ drv_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
                    MARK_NOCHANGE(CurScreen(sp), y);
                }
            }
+#endif
        }
     }
 
@@ -262,14 +442,41 @@ drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
 {
     bool code = FALSE;
 
-    T((T_CALLED("drv_CanHandle(%p)"), TCB));
+    T((T_CALLED("win32con::drv_CanHandle(%p)"), TCB));
 
     assert(TCB != 0);
     assert(tname != 0);
 
     TCB->magic = WINMAGIC;
-    if (*tname == 0 || *tname == 0 || strcmp(tname, "unknown") == 0) {
+    if (*tname == 0 || *tname == 0 || *tname == '#') {
        code = TRUE;
+    } else {
+       TERMINAL my_term;
+       int status;
+
+       code = FALSE;
+#if (USE_DATABASE || USE_TERMCAP)
+       status = _nc_setup_tinfo(tname, &my_term.type);
+#else
+       status = TGETENT_NO;
+#endif
+       if (status != TGETENT_YES) {
+           const TERMTYPE *fallback = _nc_fallback(tname);
+
+           if (fallback) {
+               my_term.type = *fallback;
+               status = TGETENT_YES;
+           } else if (!strcmp(tname, "unknown")) {
+               code = TRUE;
+           }
+       }
+       if (status == TGETENT_YES) {
+           if (generic_type || hard_copy)
+               code = TRUE;
+       }
+    }
+
+    if (code) {
        if ((TCB->term.type.Booleans) == 0) {
            _nc_init_entry(&(TCB->term.type));
        }
@@ -280,7 +487,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;
@@ -320,7 +527,7 @@ drv_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
 
 static void
 drv_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
-            bool fore,
+            int fore,
             int color,
             int (*outc) (SCREEN *, int) GCC_UNUSED)
 {
@@ -384,7 +591,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;
@@ -451,7 +658,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;
@@ -556,7 +763,7 @@ MapKey(TERMINAL_CONTROL_BLOCK * TCB, WORD vKey)
 static void
 drv_release(TERMINAL_CONTROL_BLOCK * TCB)
 {
-    T((T_CALLED("drv_release(%p)"), TCB));
+    T((T_CALLED("win32con::drv_release(%p)"), TCB));
 
     AssertTCB();
     if (TCB->prop)
@@ -570,7 +777,7 @@ drv_init(TERMINAL_CONTROL_BLOCK * TCB)
 {
     DWORD num_buttons;
 
-    T((T_CALLED("drv_init(%p)"), TCB));
+    T((T_CALLED("win32con::drv_init(%p)"), TCB));
 
     AssertTCB();
 
@@ -646,9 +853,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;
 
@@ -663,10 +870,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;
 
@@ -676,9 +883,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
 )
 {
@@ -750,7 +957,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;
 
@@ -901,7 +1108,7 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
          EVENTLIST_2nd(_nc_eventlist * evl))
 {
     SCREEN *sp;
-    INPUT_RECORD inp;
+    INPUT_RECORD inp_rec;
     BOOL b;
     DWORD nRead = 0, rc = -1;
     int code = 0;
@@ -910,7 +1117,7 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
     int diff;
     bool isImmed = (milliseconds == 0);
 
-#define CONSUME() ReadConsoleInput(TCB->inp,&inp,1,&nRead)
+#define CONSUME() ReadConsoleInput(TCB->inp,&inp_rec,1,&nRead)
 
     AssertTCB();
     SetSP();
@@ -921,7 +1128,7 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
     if (milliseconds < 0)
        milliseconds = INFINITY;
 
-    memset(&inp, 0, sizeof(inp));
+    memset(&inp_rec, 0, sizeof(inp_rec));
 
     while (true) {
        GetSystemTimeAsFileTime(&fstart);
@@ -937,15 +1144,15 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
            if (mode) {
                b = GetNumberOfConsoleInputEvents(TCB->inp, &nRead);
                if (b && nRead > 0) {
-                   b = PeekConsoleInput(TCB->inp, &inp, 1, &nRead);
+                   b = PeekConsoleInput(TCB->inp, &inp_rec, 1, &nRead);
                    if (b && nRead > 0) {
-                       switch (inp.EventType) {
+                       switch (inp_rec.EventType) {
                        case KEY_EVENT:
                            if (mode & TW_INPUT) {
-                               WORD vk = inp.Event.KeyEvent.wVirtualKeyCode;
-                               char ch = inp.Event.KeyEvent.uChar.AsciiChar;
+                               WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
+                               char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar;
 
-                               if (inp.Event.KeyEvent.bKeyDown) {
+                               if (inp_rec.Event.KeyEvent.bKeyDown) {
                                    if (0 == ch) {
                                        int nKey = MapKey(TCB, vk);
                                        if ((nKey < 0) || FALSE == sp->_keypad_on) {
@@ -962,7 +1169,7 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
                            continue;
                        case MOUSE_EVENT:
                            if (decode_mouse(TCB,
-                                            (inp.Event.MouseEvent.dwButtonState
+                                            (inp_rec.Event.MouseEvent.dwButtonState
                                              & BUTTON_MASK)) == 0) {
                                CONSUME();
                            } else if (mode & TW_MOUSE) {
@@ -1048,27 +1255,25 @@ drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
 {
     SCREEN *sp;
     int n = 1;
-    INPUT_RECORD inp;
+    INPUT_RECORD inp_rec;
     BOOL b;
     DWORD nRead;
     WORD vk;
-    WORD sc;
 
     AssertTCB();
     assert(buf);
     SetSP();
 
-    memset(&inp, 0, sizeof(inp));
+    memset(&inp_rec, 0, sizeof(inp_rec));
 
-    T((T_CALLED("drv_read(%p)"), TCB));
-    while ((b = ReadConsoleInput(TCB->inp, &inp, 1, &nRead))) {
+    T((T_CALLED("win32con::drv_read(%p)"), TCB));
+    while ((b = ReadConsoleInput(TCB->inp, &inp_rec, 1, &nRead))) {
        if (b && nRead > 0) {
-           if (inp.EventType == KEY_EVENT) {
-               if (!inp.Event.KeyEvent.bKeyDown)
+           if (inp_rec.EventType == KEY_EVENT) {
+               if (!inp_rec.Event.KeyEvent.bKeyDown)
                    continue;
-               *buf = (int) inp.Event.KeyEvent.uChar.AsciiChar;
-               vk = inp.Event.KeyEvent.wVirtualKeyCode;
-               sc = inp.Event.KeyEvent.wVirtualScanCode;
+               *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar;
+               vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
                if (*buf == 0) {
                    if (sp->_keypad_on) {
                        *buf = MapKey(TCB, vk);
@@ -1081,8 +1286,8 @@ drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
                } else {        /* *buf != 0 */
                    break;
                }
-           } else if (inp.EventType == MOUSE_EVENT) {
-               if (handle_mouse(TCB, inp.Event.MouseEvent)) {
+           } else if (inp_rec.EventType == MOUSE_EVENT) {
+               if (handle_mouse(TCB, inp_rec.Event.MouseEvent)) {
                    *buf = KEY_MOUSE;
                    break;
                }
@@ -1129,7 +1334,7 @@ drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int keycode)
 }
 
 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;
@@ -1144,7 +1349,7 @@ drv_kpad(TERMINAL_CONTROL_BLOCK * TCB, bool flag GCC_UNUSED)
 }
 
 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;