1/****************************************************************************
2 * Copyright 2018,2020 Thomas E. Dickey                                     *
3 * Copyright 2008-2016,2017 Free Software Foundation, Inc.                  *
4 *                                                                          *
5 * Permission is hereby granted, free of charge, to any person obtaining a  *
6 * copy of this software and associated documentation files (the            *
7 * "Software"), to deal in the Software without restriction, including      *
8 * without limitation the rights to use, copy, modify, merge, publish,      *
9 * distribute, distribute with modifications, sublicense, and/or sell       *
10 * copies of the Software, and to permit persons to whom the Software is    *
11 * furnished to do so, subject to the following conditions:                 *
12 *                                                                          *
13 * The above copyright notice and this permission notice shall be included  *
14 * in all copies or substantial portions of the Software.                   *
15 *                                                                          *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
19 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
23 *                                                                          *
24 * Except as contained in this notice, the name(s) of the above copyright   *
25 * holders shall not be used in advertising or otherwise to promote the     *
26 * sale, use or other dealings in this Software without prior written       *
27 * authorization.                                                           *
28 ****************************************************************************/
29
30/****************************************************************************
31 *  Author: Juergen Pfeifer                                                 *
32 *     and: Thomas E. Dickey                                                *
33 ****************************************************************************/
34
35/*
36 * TODO - improve screen-repainting performance, using implied wraparound to reduce write's
37 * TODO - make it optional whether screen is restored or not when non-buffered
38 */
39
40#include <curses.priv.h>
41#ifdef _NC_WINDOWS
42#if (defined(__MINGW32__) || defined(__MINGW64__))
43#include <wchar.h>
44#else
45#include <tchar.h>
46#endif
47#include <io.h>
48
49#define CUR TerminalType(my_term).
50
51MODULE_ID("$Id: win32_driver.c,v 1.2 2020/11/21 23:35:56 tom Exp $")
52
53#define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
54#define EXP_OPTIMIZE 0
55
56static bool console_initialized = FALSE;
57
58#define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC))
59#define validateConsoleHandle() (AssertTCB() , console_initialized ||\
60                                 (console_initialized=\
61                                  _nc_console_checkinit(TRUE,FALSE)))
62#define SetSP() assert(TCB->csp != 0); sp = TCB->csp; (void) sp
63#define AdjustY() (WINCONSOLE.buffered ?\
64                   0 : (int) WINCONSOLE.SBI.srWindow.Top)
65#define RevAttr(attr) (WORD) (((attr) & 0xff00) |   \
66                              ((((attr) & 0x07) << 4) | \
67                               (((attr) & 0x70) >> 4)))
68
69#if USE_WIDEC_SUPPORT
70#define write_screen WriteConsoleOutputW
71#define read_screen  ReadConsoleOutputW
72#else
73#define write_screen WriteConsoleOutput
74#define read_screen  ReadConsoleOutput
75#endif
76
77static WORD
78MapAttr(WORD res, attr_t ch)
79{
80    if (ch & A_COLOR) {
81	int p;
82
83	p = PairNumber(ch);
84	if (p > 0 && p < CON_NUMPAIRS) {
85	    WORD a;
86	    a = WINCONSOLE.pairs[p];
87	    res = (WORD) ((res & 0xff00) | a);
88	}
89    }
90
91    if (ch & A_REVERSE) {
92	res = RevAttr(res);
93    }
94
95    if (ch & A_STANDOUT) {
96	res = RevAttr(res) | BACKGROUND_INTENSITY;
97    }
98
99    if (ch & A_BOLD)
100	res |= FOREGROUND_INTENSITY;
101
102    if (ch & A_DIM)
103	res |= BACKGROUND_INTENSITY;
104
105    return res;
106}
107
108#if 0				/* def TRACE */
109static void
110dump_screen(const char *fn, int ln)
111{
112    int max_cells = (WINCONSOLE.SBI.dwSize.Y *
113		     (1 + WINCONSOLE.SBI.dwSize.X)) + 1;
114    char output[max_cells];
115    CHAR_INFO save_screen[max_cells];
116    COORD save_size;
117    SMALL_RECT save_region;
118    COORD bufferCoord;
119
120    T(("dump_screen %s@%d", fn, ln));
121
122    save_region.Top = WINCONSOLE.SBI.srWindow.Top;
123    save_region.Left = WINCONSOLE.SBI.srWindow.Left;
124    save_region.Bottom = WINCONSOLE.SBI.srWindow.Bottom;
125    save_region.Right = WINCONSOLE.SBI.srWindow.Right;
126
127    save_size.X = (SHORT) (save_region.Right - save_region.Left + 1);
128    save_size.Y = (SHORT) (save_region.Bottom - save_region.Top + 1);
129
130    bufferCoord.X = bufferCoord.Y = 0;
131
132    if (read_screen(WINCONSOLE.hdl,
133		    save_screen,
134		    save_size,
135		    bufferCoord,
136		    &save_region)) {
137	int i, j;
138	int ij = 0;
139	int k = 0;
140
141	for (i = save_region.Top; i <= save_region.Bottom; ++i) {
142	    for (j = save_region.Left; j <= save_region.Right; ++j) {
143		output[k++] = save_screen[ij++].Char.AsciiChar;
144	    }
145	    output[k++] = '\n';
146	}
147	output[k] = 0;
148
149	T(("DUMP: %d,%d - %d,%d",
150	   save_region.Top,
151	   save_region.Left,
152	   save_region.Bottom,
153	   save_region.Right));
154	T(("%s", output));
155    }
156}
157
158#else
159#define dump_screen(fn,ln)	/* nothing */
160#endif
161
162#if USE_WIDEC_SUPPORT
163/*
164 * TODO: support surrogate pairs
165 * TODO: support combining characters
166 * TODO: support acsc
167 * TODO: _nc_wacs should be part of sp.
168 */
169static BOOL
170con_write16(TERMINAL_CONTROL_BLOCK * TCB,
171	    int y, int x, cchar_t *str, int limit)
172{
173    int actual = 0;
174    CHAR_INFO *ci = TypeAlloca(CHAR_INFO, limit);
175    COORD loc, siz;
176    SMALL_RECT rec;
177    int i;
178    cchar_t ch;
179    SCREEN *sp;
180
181    AssertTCB();
182    SetSP();
183
184    for (i = actual = 0; i < limit; i++) {
185	ch = str[i];
186	if (isWidecExt(ch))
187	    continue;
188	ci[actual].Char.UnicodeChar = CharOf(ch);
189	ci[actual].Attributes = MapAttr(WINCONSOLE.SBI.wAttributes,
190					AttrOf(ch));
191	if (AttrOf(ch) & A_ALTCHARSET) {
192	    if (_nc_wacs) {
193		int which = CharOf(ch);
194		if (which > 0
195		    && which < ACS_LEN
196		    && CharOf(_nc_wacs[which]) != 0) {
197		    ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]);
198		} else {
199		    ci[actual].Char.UnicodeChar = ' ';
200		}
201	    }
202	}
203	++actual;
204    }
205
206    loc.X = (SHORT) 0;
207    loc.Y = (SHORT) 0;
208    siz.X = (SHORT) actual;
209    siz.Y = 1;
210
211    rec.Left = (SHORT) x;
212    rec.Top = (SHORT) (y + AdjustY());
213    rec.Right = (SHORT) (x + limit - 1);
214    rec.Bottom = rec.Top;
215
216    return write_screen(WINCONSOLE.hdl, ci, siz, loc, &rec);
217}
218#define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n)
219#else
220static BOOL
221con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
222{
223    CHAR_INFO *ci = TypeAlloca(CHAR_INFO, n);
224    COORD loc, siz;
225    SMALL_RECT rec;
226    int i;
227    chtype ch;
228    SCREEN *sp;
229
230    AssertTCB();
231    SetSP();
232
233    for (i = 0; i < n; i++) {
234	ch = str[i];
235	ci[i].Char.AsciiChar = ChCharOf(ch);
236	ci[i].Attributes = MapAttr(WINCONSOLE.SBI.wAttributes,
237				   ChAttrOf(ch));
238	if (ChAttrOf(ch) & A_ALTCHARSET) {
239	    if (sp->_acs_map)
240		ci[i].Char.AsciiChar =
241		ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
242	}
243    }
244
245    loc.X = (short) 0;
246    loc.Y = (short) 0;
247    siz.X = (short) n;
248    siz.Y = 1;
249
250    rec.Left = (short) x;
251    rec.Top = (short) y;
252    rec.Right = (short) (x + n - 1);
253    rec.Bottom = rec.Top;
254
255    return write_screen(WINCONSOLE.hdl, ci, siz, loc, &rec);
256}
257#define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n)
258#endif
259
260#if EXP_OPTIMIZE
261/*
262 * Comparing new/current screens, determine the last column-index for a change
263 * beginning on the given row,col position.  Unlike a serial terminal, there is
264 * no cost for "moving" the "cursor" on the line as we update it.
265 */
266static int
267find_end_of_change(SCREEN *sp, int row, int col)
268{
269    int result = col;
270    struct ldat *curdat = CurScreen(sp)->_line + row;
271    struct ldat *newdat = NewScreen(sp)->_line + row;
272
273    while (col <= newdat->lastchar) {
274#if USE_WIDEC_SUPPORT
275	if (isWidecExt(curdat->text[col]) ||
276	    isWidecExt(newdat->text[col])) {
277	    result = col;
278	} else if (memcmp(&curdat->text[col],
279			  &newdat->text[col],
280			  sizeof(curdat->text[0]))) {
281	    result = col;
282	} else {
283	    break;
284	}
285#else
286	if (curdat->text[col] != newdat->text[col]) {
287	    result = col;
288	} else {
289	    break;
290	}
291#endif
292	++col;
293    }
294    return result;
295}
296
297/*
298 * Given a row,col position at the end of a change-chunk, look for the
299 * beginning of the next change-chunk.
300 */
301static int
302find_next_change(SCREEN *sp, int row, int col)
303{
304    struct ldat *curdat = CurScreen(sp)->_line + row;
305    struct ldat *newdat = NewScreen(sp)->_line + row;
306    int result = newdat->lastchar + 1;
307
308    while (++col <= newdat->lastchar) {
309#if USE_WIDEC_SUPPORT
310	if (isWidecExt(curdat->text[col]) !=
311	    isWidecExt(newdat->text[col])) {
312	    result = col;
313	    break;
314	} else if (memcmp(&curdat->text[col],
315			  &newdat->text[col],
316			  sizeof(curdat->text[0]))) {
317	    result = col;
318	    break;
319	}
320#else
321	if (curdat->text[col] != newdat->text[col]) {
322	    result = col;
323	    break;
324	}
325#endif
326    }
327    return result;
328}
329
330#define EndChange(first) \
331	find_end_of_change(sp, y, first)
332#define NextChange(last)                        \
333	find_next_change(sp, y, last)
334
335#endif /* EXP_OPTIMIZE */
336
337#define MARK_NOCHANGE(win,row)                 \
338    win->_line[row].firstchar = _NOCHANGE;     \
339    win->_line[row].lastchar  = _NOCHANGE
340
341static bool
342restore_original_screen(void)
343{
344    COORD bufferCoord;
345    bool result = FALSE;
346    SMALL_RECT save_region = WINCONSOLE.save_region;
347
348    T(("... restoring %s", WINCONSOLE.window_only ?
349       "window" : "entire buffer"));
350
351    bufferCoord.X = (SHORT) (WINCONSOLE.window_only ?
352			     WINCONSOLE.SBI.srWindow.Left : 0);
353    bufferCoord.Y = (SHORT) (WINCONSOLE.window_only ?
354			     WINCONSOLE.SBI.srWindow.Top : 0);
355
356    if (write_screen(WINCONSOLE.hdl,
357		     WINCONSOLE.save_screen,
358		     WINCONSOLE.save_size,
359		     bufferCoord,
360		     &save_region)) {
361	result = TRUE;
362	mvcur(-1, -1, LINES - 2, 0);
363	T(("... restore original screen contents ok %dx%d (%d,%d - %d,%d)",
364	   WINCONSOLE.save_size.Y,
365	   WINCONSOLE.save_size.X,
366	   save_region.Top,
367	   save_region.Left,
368	   save_region.Bottom,
369	   save_region.Right));
370    } else {
371	T(("... restore original screen contents err"));
372    }
373    return result;
374}
375
376static const char *
377wcon_name(TERMINAL_CONTROL_BLOCK * TCB)
378{
379    (void) TCB;
380    return "win32console";
381}
382
383static int
384wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
385{
386    int result = ERR;
387    int y, nonempty, n, x0, x1, Width, Height;
388    SCREEN *sp;
389
390    T((T_CALLED("win32con::wcon_doupdate(%p)"), TCB));
391    if (validateConsoleHandle()) {
392	SetSP();
393
394	Width = screen_columns(sp);
395	Height = screen_lines(sp);
396	nonempty = min(Height, NewScreen(sp)->_maxy + 1);
397
398	T(("... %dx%d clear cur:%d new:%d",
399	   Height, Width,
400	   CurScreen(sp)->_clear,
401	   NewScreen(sp)->_clear));
402
403	if (SP_PARM->_endwin == ewSuspend) {
404
405	    T(("coming back from shell mode"));
406	    NCURSES_SP_NAME(reset_prog_mode) (NCURSES_SP_ARG);
407
408	    NCURSES_SP_NAME(_nc_mvcur_resume) (NCURSES_SP_ARG);
409	    NCURSES_SP_NAME(_nc_screen_resume) (NCURSES_SP_ARG);
410	    SP_PARM->_mouse_resume(SP_PARM);
411
412	    SP_PARM->_endwin = ewRunning;
413	}
414
415	if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
416	    int x;
417#if USE_WIDEC_SUPPORT
418	    cchar_t *empty = TypeAlloca(cchar_t, Width);
419	    wchar_t blank[2] =
420	    {
421		L' ', L'\0'
422	    };
423
424	    for (x = 0; x < Width; x++)
425		setcchar(&empty[x], blank, 0, 0, 0);
426#else
427	    chtype *empty = TypeAlloca(chtype, Width);
428
429	    for (x = 0; x < Width; x++)
430		empty[x] = ' ';
431#endif
432
433	    for (y = 0; y < nonempty; y++) {
434		con_write(TCB, y, 0, empty, Width);
435		memcpy(empty,
436		       CurScreen(sp)->_line[y].text,
437		       (size_t) Width * sizeof(empty[0]));
438	    }
439	    CurScreen(sp)->_clear = FALSE;
440	    NewScreen(sp)->_clear = FALSE;
441	    touchwin(NewScreen(sp));
442	    T(("... cleared %dx%d lines @%d of screen", nonempty, Width,
443	       AdjustY()));
444	}
445
446	for (y = 0; y < nonempty; y++) {
447	    x0 = NewScreen(sp)->_line[y].firstchar;
448	    if (x0 != _NOCHANGE) {
449#if EXP_OPTIMIZE
450		int x2;
451		int limit = NewScreen(sp)->_line[y].lastchar;
452		while ((x1 = EndChange(x0)) <= limit) {
453		    while ((x2 = NextChange(x1)) <=
454			   limit && x2 <= (x1 + 2)) {
455			x1 = x2;
456		    }
457		    n = x1 - x0 + 1;
458		    memcpy(&CurScreen(sp)->_line[y].text[x0],
459			   &NewScreen(sp)->_line[y].text[x0],
460			   n * sizeof(CurScreen(sp)->_line[y].text[x0]));
461		    con_write(TCB,
462			      y,
463			      x0,
464			      &CurScreen(sp)->_line[y].text[x0], n);
465		    x0 = NextChange(x1);
466		}
467
468		/* mark line changed successfully */
469		if (y <= NewScreen(sp)->_maxy) {
470		    MARK_NOCHANGE(NewScreen(sp), y);
471		}
472		if (y <= CurScreen(sp)->_maxy) {
473		    MARK_NOCHANGE(CurScreen(sp), y);
474		}
475#else
476		x1 = NewScreen(sp)->_line[y].lastchar;
477		n = x1 - x0 + 1;
478		if (n > 0) {
479		    memcpy(&CurScreen(sp)->_line[y].text[x0],
480			   &NewScreen(sp)->_line[y].text[x0],
481			   (size_t) n *
482			   sizeof(CurScreen(sp)->_line[y].text[x0]));
483		    con_write(TCB,
484			      y,
485			      x0,
486			      &CurScreen(sp)->_line[y].text[x0], n);
487
488		    /* mark line changed successfully */
489		    if (y <= NewScreen(sp)->_maxy) {
490			MARK_NOCHANGE(NewScreen(sp), y);
491		    }
492		    if (y <= CurScreen(sp)->_maxy) {
493			MARK_NOCHANGE(CurScreen(sp), y);
494		    }
495		}
496#endif
497	    }
498	}
499
500	/* put everything back in sync */
501	for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
502	    MARK_NOCHANGE(NewScreen(sp), y);
503	}
504	for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
505	    MARK_NOCHANGE(CurScreen(sp), y);
506	}
507
508	if (!NewScreen(sp)->_leaveok) {
509	    CurScreen(sp)->_curx = NewScreen(sp)->_curx;
510	    CurScreen(sp)->_cury = NewScreen(sp)->_cury;
511
512	    TCB->drv->td_hwcur(TCB,
513			       0,
514			       0,
515			       CurScreen(sp)->_cury,
516			       CurScreen(sp)->_curx);
517	}
518	_nc_console_selectActiveHandle();
519	result = OK;
520    }
521    returnCode(result);
522}
523
524static bool
525wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
526	       const char *tname,
527	       int *errret GCC_UNUSED)
528{
529    bool code = FALSE;
530
531    T((T_CALLED("win32con::wcon_CanHandle(%p)"), TCB));
532
533    assert((TCB != 0) && (tname != 0));
534
535    TCB->magic = WINMAGIC;
536
537    if (tname == 0 || *tname == 0) {
538	if (!_nc_console_vt_supported())
539	    code = TRUE;
540    } else if (tname != 0 && *tname == '#') {
541	/*
542	 * Use "#" (a character which cannot begin a terminal's name) to
543	 * select specific driver from the table.
544	 *
545	 * In principle, we could have more than one non-terminfo driver,
546	 * e.g., "win32gui".
547	 */
548	size_t n = strlen(tname + 1);
549	if (n != 0
550	    && ((strncmp(tname + 1, "win32console", n) == 0)
551		|| (strncmp(tname + 1, "win32con", n) == 0))) {
552	    code = TRUE;
553	}
554    } else if (tname != 0 && stricmp(tname, "unknown") == 0) {
555	code = TRUE;
556    }
557
558    /*
559     * This is intentional, to avoid unnecessary breakage of applications
560     * using <term.h> symbols.
561     */
562    if (code && (TerminalType(&TCB->term).Booleans == 0)) {
563	_nc_init_termtype(&TerminalType(&TCB->term));
564#if NCURSES_EXT_NUMBERS
565	_nc_export_termtype2(&TCB->term.type, &TerminalType(&TCB->term));
566#endif
567    }
568
569    if (!code) {
570	if (_nc_console_test(0)) {
571	    T(("isTermInfoConsole=TRUE"));
572	    WINCONSOLE.isTermInfoConsole = TRUE;
573	}
574    }
575    returnBool(code);
576}
577
578static int
579wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
580		 int beepFlag)
581{
582    SCREEN *sp;
583    int res = ERR;
584
585    int high = (WINCONSOLE.SBI.srWindow.Bottom -
586		WINCONSOLE.SBI.srWindow.Top + 1);
587    int wide = (WINCONSOLE.SBI.srWindow.Right -
588		WINCONSOLE.SBI.srWindow.Left + 1);
589    int max_cells = (high * wide);
590    int i;
591
592    CHAR_INFO *this_screen = TypeAlloca(CHAR_INFO, max_cells);
593    CHAR_INFO *that_screen = TypeAlloca(CHAR_INFO, max_cells);
594    COORD this_size;
595    SMALL_RECT this_region;
596    COORD bufferCoord;
597
598    if (validateConsoleHandle()) {
599	SetSP();
600	this_region.Top = WINCONSOLE.SBI.srWindow.Top;
601	this_region.Left = WINCONSOLE.SBI.srWindow.Left;
602	this_region.Bottom = WINCONSOLE.SBI.srWindow.Bottom;
603	this_region.Right = WINCONSOLE.SBI.srWindow.Right;
604
605	this_size.X = (SHORT) wide;
606	this_size.Y = (SHORT) high;
607
608	bufferCoord.X = this_region.Left;
609	bufferCoord.Y = this_region.Top;
610
611	if (!beepFlag &&
612	    read_screen(WINCONSOLE.hdl,
613			this_screen,
614			this_size,
615			bufferCoord,
616			&this_region)) {
617
618	    memcpy(that_screen,
619		   this_screen,
620		   sizeof(CHAR_INFO) * (size_t) max_cells);
621
622	    for (i = 0; i < max_cells; i++) {
623		that_screen[i].Attributes =
624		    RevAttr(that_screen[i].Attributes);
625	    }
626
627	    write_screen(WINCONSOLE.hdl, that_screen, this_size,
628			 bufferCoord, &this_region);
629	    Sleep(200);
630	    write_screen(WINCONSOLE.hdl, this_screen, this_size,
631			 bufferCoord, &this_region);
632
633	} else {
634	    MessageBeep(MB_ICONWARNING);	/* MB_OK might be better */
635	}
636	res = OK;
637    }
638    return res;
639}
640
641static int
642wcon_print(TERMINAL_CONTROL_BLOCK * TCB,
643	   char *data GCC_UNUSED,
644	   int len GCC_UNUSED)
645{
646    SCREEN *sp;
647
648    AssertTCB();
649    SetSP();
650
651    return ERR;
652}
653
654static int
655wcon_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
656		   int fg GCC_UNUSED,
657		   int bg GCC_UNUSED)
658{
659    SCREEN *sp;
660    int code = ERR;
661
662    AssertTCB();
663    SetSP();
664
665    return (code);
666}
667
668static void
669wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
670	      int fore,
671	      int color,
672	      int (*outc) (SCREEN *, int) GCC_UNUSED)
673{
674    (void) TCB;
675    if (validateConsoleHandle()) {
676	WORD a = _nc_console_MapColor(fore, color);
677	a |= (WORD) ((WINCONSOLE.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
678	SetConsoleTextAttribute(WINCONSOLE.hdl, a);
679	_nc_console_get_SBI();
680    }
681}
682
683static bool
684wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB)
685{
686    bool res = FALSE;
687
688    (void) TCB;
689    if (validateConsoleHandle()) {
690	WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
691	SetConsoleTextAttribute(WINCONSOLE.hdl, a);
692	_nc_console_get_SBI();
693	res = TRUE;
694    }
695    return res;
696}
697
698static bool
699wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
700{
701    int result = FALSE;
702    SCREEN *sp;
703
704    AssertTCB();
705    SetSP();
706
707    return result;
708}
709
710static int
711wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
712{
713    int result = ERR;
714
715    T((T_CALLED("win32con::wcon_size(%p)"), TCB));
716
717    if (validateConsoleHandle() &&
718	(Lines != NULL) && (Cols != NULL)) {
719	_nc_console_size(Lines, Cols);
720	result = OK;
721    }
722    returnCode(result);
723}
724
725static int
726wcon_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
727	     int l GCC_UNUSED,
728	     int c GCC_UNUSED)
729{
730    AssertTCB();
731    return ERR;
732}
733
734static int
735wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
736{
737    int result = ERR;
738
739    T((T_CALLED("win32con::wcon_sgmode(TCB=(%p),setFlag=%d,TTY=(%p)"),
740       TCB, setFlag, buf));
741    if (buf != NULL && validateConsoleHandle()) {
742
743	if (setFlag) {
744	    _nc_console_setmode(WINCONSOLE.hdl, buf);
745	    TCB->term.Nttyb = *buf;
746	} else {
747	    _nc_console_getmode(WINCONSOLE.hdl, &(TCB->term.Nttyb));
748	    *buf = TCB->term.Nttyb;
749	}
750	result = OK;
751    }
752    returnCode(result);
753}
754
755#define MIN_WIDE 80
756#define MIN_HIGH 24
757
758static int
759wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
760{
761    SCREEN *sp;
762    TERMINAL *_term = (TERMINAL *) TCB;
763    int code = ERR;
764
765    if (validateConsoleHandle()) {
766	sp = TCB->csp;
767
768	T((T_CALLED("win32con::wcon_mode(%p, progFlag=%d, defFlag=%d)"),
769	   TCB, progFlag, defFlag));
770
771	WINCONSOLE.progMode = progFlag;
772	WINCONSOLE.lastOut = progFlag ? WINCONSOLE.hdl : WINCONSOLE.out;
773	SetConsoleActiveScreenBuffer(WINCONSOLE.lastOut);
774
775	if (progFlag) /* prog mode */  {
776	    if (defFlag) {
777		if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
778		    code = OK;
779		}
780	    } else {
781		/* reset_prog_mode */
782		if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
783		    if (sp) {
784			if (sp->_keypad_on)
785			    _nc_keypad(sp, TRUE);
786		    }
787		    if (!WINCONSOLE.buffered) {
788			_nc_console_set_scrollback(FALSE, &WINCONSOLE.SBI);
789		    }
790		    code = OK;
791		}
792	    }
793	    T(("... buffered:%d, clear:%d",
794	       WINCONSOLE.buffered, CurScreen(sp)->_clear));
795	} else {		/* shell mode */
796	    if (defFlag) {
797		/* def_shell_mode */
798		if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
799		    code = OK;
800		}
801	    } else {
802		/* reset_shell_mode */
803		if (sp) {
804		    _nc_keypad(sp, FALSE);
805		    NCURSES_SP_NAME(_nc_flush) (sp);
806		}
807		code = wcon_sgmode(TCB, TRUE, &(_term->Ottyb));
808		if (!WINCONSOLE.buffered) {
809		    _nc_console_set_scrollback(TRUE, &WINCONSOLE.save_SBI);
810		    if (!restore_original_screen())
811			code = ERR;
812		}
813		SetConsoleCursorInfo(WINCONSOLE.hdl, &WINCONSOLE.save_CI);
814	    }
815	}
816
817    }
818    returnCode(code);
819}
820
821static void
822wcon_screen_init(SCREEN *sp GCC_UNUSED)
823{
824}
825
826static void
827wcon_wrap(SCREEN *sp GCC_UNUSED)
828{
829}
830
831static void
832wcon_release(TERMINAL_CONTROL_BLOCK * TCB)
833{
834    T((T_CALLED("win32con::wcon_release(%p)"), TCB));
835
836    AssertTCB();
837    if (TCB->prop)
838	free(TCB->prop);
839
840    returnVoid;
841}
842
843static void
844wcon_init(TERMINAL_CONTROL_BLOCK * TCB)
845{
846    T((T_CALLED("win32con::wcon_init(%p)"), TCB));
847
848    AssertTCB();
849
850    if (!(console_initialized = _nc_console_checkinit(TRUE, FALSE))) {
851	returnVoid;
852    }
853
854    if (TCB) {
855	TCB->info.initcolor = TRUE;
856	TCB->info.canchange = FALSE;
857	TCB->info.hascolor = TRUE;
858	TCB->info.caninit = TRUE;
859
860	TCB->info.maxpairs = CON_NUMPAIRS;
861	TCB->info.maxcolors = 8;
862	TCB->info.numlabels = 0;
863	TCB->info.labelwidth = 0;
864	TCB->info.labelheight = 0;
865	TCB->info.nocolorvideo = 1;
866	TCB->info.tabsize = 8;
867
868	TCB->info.numbuttons = WINCONSOLE.numButtons;
869	TCB->info.defaultPalette = _nc_cga_palette;
870
871    }
872    returnVoid;
873}
874
875static void
876wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB,
877	      int pair,
878	      int f,
879	      int b)
880{
881    SCREEN *sp;
882
883    if (validateConsoleHandle()) {
884	SetSP();
885
886	if ((pair > 0) && (pair < CON_NUMPAIRS) && (f >= 0) && (f < 8)
887	    && (b >= 0) && (b < 8)) {
888	    WINCONSOLE.pairs[pair] =
889		_nc_console_MapColor(true, f) |
890		_nc_console_MapColor(false, b);
891	}
892    }
893}
894
895static void
896wcon_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
897	       int color GCC_UNUSED,
898	       int r GCC_UNUSED,
899	       int g GCC_UNUSED,
900	       int b GCC_UNUSED)
901{
902    SCREEN *sp;
903
904    AssertTCB();
905    SetSP();
906}
907
908static void
909wcon_do_color(TERMINAL_CONTROL_BLOCK * TCB,
910	      int old_pair GCC_UNUSED,
911	      int pair GCC_UNUSED,
912	      int reverse GCC_UNUSED,
913	      int (*outc) (SCREEN *, int) GCC_UNUSED
914)
915{
916    SCREEN *sp;
917
918    AssertTCB();
919    SetSP();
920}
921
922static void
923wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
924{
925    SCREEN *sp;
926
927    if (validateConsoleHandle()) {
928	SetSP();
929
930	sp->_mouse_type = M_TERM_DRIVER;
931    }
932}
933
934static int
935wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB,
936	       int delay
937	       EVENTLIST_2nd(_nc_eventlist * evl))
938{
939    int rc = 0;
940    SCREEN *sp;
941
942    if (validateConsoleHandle()) {
943	SetSP();
944
945	if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
946	    rc = TW_MOUSE;
947	} else {
948	    rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
949					  TWAIT_MASK,
950					  delay,
951					  (int *) 0
952					  EVENTLIST_2nd(evl));
953	}
954    }
955
956    return rc;
957}
958
959static int
960wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
961	   int yold GCC_UNUSED, int xold GCC_UNUSED,
962	   int y, int x)
963{
964    int ret = ERR;
965
966    (void) TCB;
967    if (validateConsoleHandle()) {
968	COORD loc;
969	loc.X = (short) x;
970	loc.Y = (short) (y + AdjustY());
971	SetConsoleCursorPosition(WINCONSOLE.hdl, loc);
972	ret = OK;
973    }
974    return ret;
975}
976
977static void
978wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
979	     int labnum GCC_UNUSED,
980	     char *text GCC_UNUSED)
981{
982    SCREEN *sp;
983
984    AssertTCB();
985    SetSP();
986}
987
988static void
989wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
990		  int OnFlag GCC_UNUSED)
991{
992    SCREEN *sp;
993
994    AssertTCB();
995    SetSP();
996}
997
998static chtype
999wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
1000{
1001    chtype res = A_NORMAL;
1002    res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
1003    return res;
1004}
1005
1006static void
1007wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
1008{
1009    SCREEN *sp;
1010
1011    AssertTCB();
1012    SetSP();
1013}
1014
1015static void
1016wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB,
1017	     chtype *real_map GCC_UNUSED,
1018	     chtype *fake_map GCC_UNUSED)
1019{
1020#define DATA(a,b) { a, b }
1021    static struct {
1022	int acs_code;
1023	int use_code;
1024    } table[] = {
1025	DATA('a', 0xb1),	/* ACS_CKBOARD  */
1026	    DATA('f', 0xf8),	/* ACS_DEGREE   */
1027	    DATA('g', 0xf1),	/* ACS_PLMINUS  */
1028	    DATA('j', 0xd9),	/* ACS_LRCORNER */
1029	    DATA('l', 0xda),	/* ACS_ULCORNER */
1030	    DATA('k', 0xbf),	/* ACS_URCORNER */
1031	    DATA('m', 0xc0),	/* ACS_LLCORNER */
1032	    DATA('n', 0xc5),	/* ACS_PLUS     */
1033	    DATA('q', 0xc4),	/* ACS_HLINE    */
1034	    DATA('t', 0xc3),	/* ACS_LTEE     */
1035	    DATA('u', 0xb4),	/* ACS_RTEE     */
1036	    DATA('v', 0xc1),	/* ACS_BTEE     */
1037	    DATA('w', 0xc2),	/* ACS_TTEE     */
1038	    DATA('x', 0xb3),	/* ACS_VLINE    */
1039	    DATA('y', 0xf3),	/* ACS_LEQUAL   */
1040	    DATA('z', 0xf2),	/* ACS_GEQUAL   */
1041	    DATA('0', 0xdb),	/* ACS_BLOCK    */
1042	    DATA('{', 0xe3),	/* ACS_PI       */
1043	    DATA('}', 0x9c),	/* ACS_STERLING */
1044	    DATA(',', 0xae),	/* ACS_LARROW   */
1045	    DATA('+', 0xaf),	/* ACS_RARROW   */
1046	    DATA('~', 0xf9),	/* ACS_BULLET   */
1047    };
1048#undef DATA
1049    unsigned n;
1050
1051    SCREEN *sp;
1052    if (validateConsoleHandle()) {
1053	SetSP();
1054
1055	for (n = 0; n < SIZEOF(table); ++n) {
1056	    real_map[table[n].acs_code] =
1057		(chtype) table[n].use_code | A_ALTCHARSET;
1058	    if (sp != 0)
1059		sp->_screen_acs_map[table[n].acs_code] = TRUE;
1060	}
1061    }
1062}
1063
1064static int
1065wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,
1066	   int mode,
1067	   int milliseconds,
1068	   int *timeleft
1069	   EVENTLIST_2nd(_nc_eventlist * evl))
1070{
1071    SCREEN *sp;
1072    int code = 0;
1073
1074    if (validateConsoleHandle()) {
1075	SetSP();
1076
1077	code = _nc_console_twait(sp,
1078				 WINCONSOLE.inp,
1079				 mode,
1080				 milliseconds,
1081				 timeleft EVENTLIST_2nd(evl));
1082    }
1083    return code;
1084}
1085
1086static int
1087wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
1088{
1089    SCREEN *sp;
1090    int n = -1;
1091
1092    T((T_CALLED("win32con::wcon_read(%p)"), TCB));
1093
1094    assert(buf);
1095    if (validateConsoleHandle()) {
1096	SetSP();
1097
1098	n = _nc_console_read(sp, WINCONSOLE.inp, buf);
1099    }
1100    returnCode(n);
1101}
1102
1103static int
1104wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
1105{
1106    T((T_CALLED("win32con::wcon_nap(%p, %d)"), TCB, ms));
1107    Sleep((DWORD) ms);
1108    returnCode(OK);
1109}
1110
1111static int
1112wcon_cursorSet(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int mode)
1113{
1114    int res = -1;
1115
1116    T((T_CALLED("win32con:wcon_cursorSet(%d)"), mode));
1117    if (validateConsoleHandle()) {
1118	CONSOLE_CURSOR_INFO this_CI = WINCONSOLE.save_CI;
1119	switch (mode) {
1120	case 0:
1121	    this_CI.bVisible = FALSE;
1122	    break;
1123	case 1:
1124	    break;
1125	case 2:
1126	    this_CI.dwSize = 100;
1127	    break;
1128	}
1129	SetConsoleCursorInfo(WINCONSOLE.hdl, &this_CI);
1130    }
1131    returnCode(res);
1132}
1133
1134static bool
1135wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode)
1136{
1137    bool found = FALSE;
1138
1139    T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode));
1140    found = _nc_console_keyExist(keycode);
1141    returnBool(found);
1142}
1143
1144static int
1145wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
1146{
1147    SCREEN *sp;
1148    int code = ERR;
1149
1150    T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag));
1151
1152    if (validateConsoleHandle()) {
1153	SetSP();
1154
1155	if (sp) {
1156	    code = OK;
1157	}
1158    }
1159    returnCode(code);
1160}
1161
1162static int
1163wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB,
1164	   int keycode,
1165	   int flag)
1166{
1167    int code = ERR;
1168    SCREEN *sp;
1169
1170    T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag));
1171
1172    if (validateConsoleHandle()) {
1173	SetSP();
1174	if (sp) {
1175	    code = _nc_console_keyok(keycode, flag);
1176	}
1177    }
1178    returnCode(code);
1179}
1180
1181NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
1182    FALSE,
1183	wcon_name,		/* Name          */
1184	wcon_CanHandle,		/* CanHandle     */
1185	wcon_init,		/* init          */
1186	wcon_release,		/* release       */
1187	wcon_size,		/* size          */
1188	wcon_sgmode,		/* sgmode        */
1189	wcon_conattr,		/* conattr       */
1190	wcon_mvcur,		/* hwcur         */
1191	wcon_mode,		/* mode          */
1192	wcon_rescol,		/* rescol        */
1193	wcon_rescolors,		/* rescolors     */
1194	wcon_setcolor,		/* color         */
1195	wcon_dobeepflash,	/* DoBeepFlash   */
1196	wcon_initpair,		/* initpair      */
1197	wcon_initcolor,		/* initcolor     */
1198	wcon_do_color,		/* docolor       */
1199	wcon_initmouse,		/* initmouse     */
1200	wcon_testmouse,		/* testmouse     */
1201	wcon_setfilter,		/* setfilter     */
1202	wcon_hwlabel,		/* hwlabel       */
1203	wcon_hwlabelOnOff,	/* hwlabelOnOff  */
1204	wcon_doupdate,		/* update        */
1205	wcon_defaultcolors,	/* defaultcolors */
1206	wcon_print,		/* print         */
1207	wcon_size,		/* getsize       */
1208	wcon_setsize,		/* setsize       */
1209	wcon_initacs,		/* initacs       */
1210	wcon_screen_init,	/* scinit        */
1211	wcon_wrap,		/* scexit        */
1212	wcon_twait,		/* twait         */
1213	wcon_read,		/* read          */
1214	wcon_nap,		/* nap           */
1215	wcon_kpad,		/* kpad          */
1216	wcon_keyok,		/* kyOk          */
1217	wcon_kyExist,		/* kyExist       */
1218	wcon_cursorSet		/* cursorSet     */
1219};
1220
1221#endif /* _NC_WINDOWS */
1222