X-Git-Url: https://ncurses.scripts.mit.edu/?a=blobdiff_plain;f=ncurses%2Fwin32con%2Fwin_driver.c;h=51e4d0f5d999fcb61b2659157610db6c22e6f7ee;hb=8966d257503a5eb02998b885eb376d50d7e16eda;hp=afc1a16815b7ccb83a4bbb8f4ba3bd0650271ba4;hpb=cdbe3d3df7ca08989c4aaead5164309466e519eb;p=ncurses.git diff --git a/ncurses/win32con/win_driver.c b/ncurses/win32con/win_driver.c index afc1a168..51e4d0f5 100644 --- a/ncurses/win32con/win_driver.c +++ b/ncurses/win32con/win_driver.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998-2010,2012 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 * @@ -38,12 +38,16 @@ #include #define CUR my_term.type. -MODULE_ID("$Id: win_driver.c,v 1.13 2012/09/03 16:20:24 tom Exp $") +MODULE_ID("$Id: win_driver.c,v 1.18 2013/03/02 19:48:06 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; (void) sp +#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) @@ -68,6 +72,7 @@ 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]; @@ -143,9 +148,10 @@ MapAttr(TERMINAL_CONTROL_BLOCK * TCB, WORD res, attr_t ch) * TODO: _nc_wacs should be part of sp. */ static BOOL -con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int n) +con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit) { - CHAR_INFO ci[n]; + int actual = 0; + CHAR_INFO ci[limit]; COORD loc, siz; SMALL_RECT rec; int i; @@ -154,39 +160,39 @@ con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int n) AssertTCB(); - if (TCB == 0 || InvalidConsoleHandle(TCB->hdl)) - return FALSE; - SetSP(); - for (i = 0; i < n; i++) { + for (i = actual = 0; i < limit; i++) { ch = str[i]; - ci[i].Char.UnicodeChar = CharOf(ch); - ci[i].Attributes = MapAttr(TCB, - PropOf(TCB)->SBI.wAttributes, - AttrOf(ch)); + 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[i].Char.UnicodeChar = CharOf(_nc_wacs[which]); + ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]); } else { - ci[i].Char.UnicodeChar = ' '; + ci[actual].Char.UnicodeChar = ' '; } } } + ++actual; } loc.X = (short) 0; loc.Y = (short) 0; - siz.X = (short) n; + siz.X = (short) actual; siz.Y = 1; rec.Left = (short) x; rec.Top = (short) y; - rec.Right = (short) (x + n - 1); + rec.Right = (short) (x + limit - 1); rec.Bottom = rec.Top; return WriteConsoleOutputW(TCB->hdl, ci, siz, loc, &rec); @@ -205,9 +211,6 @@ con_write8(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++) { @@ -238,65 +241,160 @@ con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n) #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; + Width = screen_columns(sp); + Height = screen_lines(sp); + nonempty = min(Height, NewScreen(sp)->_maxy + 1); + + 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); + 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]; + chtype empty[Width]; - for (x = 0; x < Width; x++) - empty[x] = ' '; + 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(empty[0])); + for (y = 0; y < nonempty; y++) { + con_write(TCB, y, 0, empty, Width); + memcpy(empty, + CurScreen(sp)->_line[y].text, + 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(CurScreen(sp)->_line[y].text[x0])); - con_write(TCB, - y, - x0, - &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) { @@ -305,26 +403,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], + 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 @@ -340,7 +462,7 @@ 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; @@ -425,7 +547,7 @@ drv_setcolor(TERMINAL_CONTROL_BLOCK * TCB, { AssertTCB(); - if (TCB && !InvalidConsoleHandle(TCB->hdl)) { + if (okConsoleHandle(TCB)) { WORD a = MapColor(fore, color); a = ((PropOf(TCB)->SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f)) | a; SetConsoleTextAttribute(TCB->hdl, a); @@ -439,7 +561,7 @@ 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)); @@ -463,14 +585,20 @@ 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) && + Lines != NULL && + Cols != NULL) { + *Lines = (int) (PropOf(TCB)->SBI.dwSize.Y); + *Cols = (int) (PropOf(TCB)->SBI.dwSize.X); + result = OK; + } + returnCode(result); } static int @@ -560,7 +688,8 @@ drv_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int 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) { @@ -826,7 +955,7 @@ drv_mvcur(TERMINAL_CONTROL_BLOCK * TCB, int y, int x) { int ret = ERR; - if (TCB && !InvalidConsoleHandle(TCB->hdl)) { + if (okConsoleHandle(TCB)) { COORD loc; loc.X = (short) x; loc.Y = (short) y; @@ -1070,8 +1199,7 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB, } continue; default: - SetConsoleActiveScreenBuffer(!PropOf(TCB)->progMode ? - TCB->hdl : TCB->out); + selectActiveHandle(TCB); continue; } } @@ -1193,8 +1321,9 @@ drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf) static int drv_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms) { + T((T_CALLED("win32con::drv_nap(%p, %d)"), TCB, ms)); Sleep(ms); - return OK; + returnCode(OK); } static bool @@ -1211,6 +1340,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), @@ -1222,7 +1352,7 @@ drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int keycode) if (!(nKey & 0x8000)) found = TRUE; } - return found; + returnCode(found); } static int @@ -1234,10 +1364,11 @@ drv_kpad(TERMINAL_CONTROL_BLOCK * TCB, int 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 @@ -1253,6 +1384,7 @@ drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, int flag) AssertTCB(); SetSP(); + T((T_CALLED("win32con::drv_keyok(%p, %d, %d)"), TCB, keycode, flag)); if (sp) { res = bsearch(&key, PropOf(TCB)->rmap, @@ -1268,7 +1400,7 @@ drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, int flag) *(LONG *) res = GenMap(vKey, nKey); } } - return code; + returnCode(code); } NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {