/****************************************************************************
- * 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 *
/****************************************************************************
* 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)
}
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;
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;
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; \
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;
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) {
MARK_NOCHANGE(CurScreen(sp), y);
}
}
+#endif
}
}
{
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));
}
static int
drv_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
- bool beepFlag GCC_UNUSED)
+ int beepFlag GCC_UNUSED)
{
SCREEN *sp;
int res = ERR;
static void
drv_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
- bool fore,
+ int fore,
int color,
int (*outc) (SCREEN *, int) 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;
}
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;
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)
{
DWORD num_buttons;
- T((T_CALLED("drv_init(%p)"), TCB));
+ T((T_CALLED("win32con::drv_init(%p)"), TCB));
AssertTCB();
static void
drv_initpair(TERMINAL_CONTROL_BLOCK * TCB,
- short pair,
- short f,
- short b)
+ int pair,
+ int f,
+ int b)
{
SCREEN *sp;
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;
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
)
{
static void
drv_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
- bool OnFlag GCC_UNUSED)
+ int OnFlag GCC_UNUSED)
{
SCREEN *sp;
EVENTLIST_2nd(_nc_eventlist * evl))
{
SCREEN *sp;
- INPUT_RECORD inp;
+ INPUT_RECORD inp_rec;
BOOL b;
DWORD nRead = 0, rc = -1;
int code = 0;
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();
if (milliseconds < 0)
milliseconds = INFINITY;
- memset(&inp, 0, sizeof(inp));
+ memset(&inp_rec, 0, sizeof(inp_rec));
while (true) {
GetSystemTimeAsFileTime(&fstart);
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) {
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) {
{
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);
} 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;
}
}
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;
}
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;