ncurses 6.2 - patch 20201017
[ncurses.git] / ncurses / win32con / win32_driver.c
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
51 MODULE_ID("$Id: win32_driver.c,v 1.1 2020/08/29 19:26:24 tom Exp $")
52
53 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
54 #define EXP_OPTIMIZE 0
55
56 static 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
77 static WORD
78 MapAttr(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 */
109 static void
110 dump_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  */
169 static BOOL
170 con_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
220 static BOOL
221 con_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  */
266 static int
267 find_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  */
301 static int
302 find_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
341 static bool
342 restore_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
376 static const char *
377 wcon_name(TERMINAL_CONTROL_BLOCK * TCB)
378 {
379     (void) TCB;
380     return "win32console";
381 }
382
383 static int
384 wcon_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
524 static bool
525 wcon_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
578 static int
579 wcon_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
641 static int
642 wcon_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
654 static int
655 wcon_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
668 static void
669 wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
670               int fore,
671               int color,
672               int (*outc) (SCREEN *, int) GCC_UNUSED)
673 {
674     if (validateConsoleHandle()) {
675         WORD a = _nc_console_MapColor(fore, color);
676         a |= (WORD) ((WINCONSOLE.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
677         SetConsoleTextAttribute(WINCONSOLE.hdl, a);
678         _nc_console_get_SBI();
679     }
680 }
681
682 static bool
683 wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB)
684 {
685     bool res = FALSE;
686
687     if (validateConsoleHandle()) {
688         WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
689         SetConsoleTextAttribute(WINCONSOLE.hdl, a);
690         _nc_console_get_SBI();
691         res = TRUE;
692     }
693     return res;
694 }
695
696 static bool
697 wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
698 {
699     int result = FALSE;
700     SCREEN *sp;
701
702     AssertTCB();
703     SetSP();
704
705     return result;
706 }
707
708 static int
709 wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
710 {
711     int result = ERR;
712
713     T((T_CALLED("win32con::wcon_size(%p)"), TCB));
714
715     if (validateConsoleHandle() &&
716         (Lines != NULL) && (Cols != NULL)) {
717         _nc_console_size(Lines, Cols);
718         result = OK;
719     }
720     returnCode(result);
721 }
722
723 static int
724 wcon_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
725              int l GCC_UNUSED,
726              int c GCC_UNUSED)
727 {
728     AssertTCB();
729     return ERR;
730 }
731
732 static int
733 wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
734 {
735     TERMINAL *_term = (TERMINAL *) TCB;
736     int result = ERR;
737
738     T((T_CALLED("win32con::wcon_sgmode(TCB=(%p),setFlag=%d,TTY=(%p)"),
739        TCB, setFlag, buf));
740     if (buf != NULL && validateConsoleHandle()) {
741
742         if (setFlag) {
743             _nc_console_setmode(WINCONSOLE.hdl, buf);
744             TCB->term.Nttyb = *buf;
745         } else {
746             _nc_console_getmode(WINCONSOLE.hdl, &(TCB->term.Nttyb));
747             *buf = TCB->term.Nttyb;
748         }
749         result = OK;
750     }
751     returnCode(result);
752 }
753
754 #define MIN_WIDE 80
755 #define MIN_HIGH 24
756
757 static int
758 wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
759 {
760     SCREEN *sp;
761     TERMINAL *_term = (TERMINAL *) TCB;
762     int code = ERR;
763
764     if (validateConsoleHandle()) {
765         sp = TCB->csp;
766
767         T((T_CALLED("win32con::wcon_mode(%p, progFlag=%d, defFlag=%d)"),
768            TCB, progFlag, defFlag));
769
770         WINCONSOLE.progMode = progFlag;
771         WINCONSOLE.lastOut = progFlag ? WINCONSOLE.hdl : WINCONSOLE.out;
772         SetConsoleActiveScreenBuffer(WINCONSOLE.lastOut);
773
774         if (progFlag) /* prog mode */  {
775             if (defFlag) {
776                 if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
777                     code = OK;
778                 }
779             } else {
780                 /* reset_prog_mode */
781                 if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
782                     if (sp) {
783                         if (sp->_keypad_on)
784                             _nc_keypad(sp, TRUE);
785                     }
786                     if (!WINCONSOLE.buffered) {
787                         _nc_console_set_scrollback(FALSE, &WINCONSOLE.SBI);
788                     }
789                     code = OK;
790                 }
791             }
792             T(("... buffered:%d, clear:%d",
793                WINCONSOLE.buffered, CurScreen(sp)->_clear));
794         } else {                /* shell mode */
795             if (defFlag) {
796                 /* def_shell_mode */
797                 if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
798                     code = OK;
799                 }
800             } else {
801                 /* reset_shell_mode */
802                 if (sp) {
803                     _nc_keypad(sp, FALSE);
804                     NCURSES_SP_NAME(_nc_flush) (sp);
805                 }
806                 code = wcon_sgmode(TCB, TRUE, &(_term->Ottyb));
807                 if (!WINCONSOLE.buffered) {
808                     _nc_console_set_scrollback(TRUE, &WINCONSOLE.save_SBI);
809                     if (!restore_original_screen())
810                         code = ERR;
811                 }
812                 SetConsoleCursorInfo(WINCONSOLE.hdl, &WINCONSOLE.save_CI);
813             }
814         }
815
816     }
817     returnCode(code);
818 }
819
820 static void
821 wcon_screen_init(SCREEN *sp GCC_UNUSED)
822 {
823 }
824
825 static void
826 wcon_wrap(SCREEN *sp GCC_UNUSED)
827 {
828 }
829
830 static void
831 wcon_release(TERMINAL_CONTROL_BLOCK * TCB)
832 {
833     T((T_CALLED("win32con::wcon_release(%p)"), TCB));
834
835     AssertTCB();
836     if (TCB->prop)
837         free(TCB->prop);
838
839     returnVoid;
840 }
841
842 static void
843 wcon_init(TERMINAL_CONTROL_BLOCK * TCB)
844 {
845     T((T_CALLED("win32con::wcon_init(%p)"), TCB));
846
847     AssertTCB();
848
849     if (!(console_initialized = _nc_console_checkinit(TRUE, FALSE))) {
850         returnVoid;
851     }
852
853     if (TCB) {
854         TCB->info.initcolor = TRUE;
855         TCB->info.canchange = FALSE;
856         TCB->info.hascolor = TRUE;
857         TCB->info.caninit = TRUE;
858
859         TCB->info.maxpairs = CON_NUMPAIRS;
860         TCB->info.maxcolors = 8;
861         TCB->info.numlabels = 0;
862         TCB->info.labelwidth = 0;
863         TCB->info.labelheight = 0;
864         TCB->info.nocolorvideo = 1;
865         TCB->info.tabsize = 8;
866
867         TCB->info.numbuttons = WINCONSOLE.numButtons;
868         TCB->info.defaultPalette = _nc_cga_palette;
869
870     }
871     returnVoid;
872 }
873
874 static void
875 wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB,
876               int pair,
877               int f,
878               int b)
879 {
880     SCREEN *sp;
881
882     if (validateConsoleHandle()) {
883         SetSP();
884
885         if ((pair > 0) && (pair < CON_NUMPAIRS) && (f >= 0) && (f < 8)
886             && (b >= 0) && (b < 8)) {
887             WINCONSOLE.pairs[pair] =
888                 _nc_console_MapColor(true, f) |
889                 _nc_console_MapColor(false, b);
890         }
891     }
892 }
893
894 static void
895 wcon_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
896                int color GCC_UNUSED,
897                int r GCC_UNUSED,
898                int g GCC_UNUSED,
899                int b GCC_UNUSED)
900 {
901     SCREEN *sp;
902
903     AssertTCB();
904     SetSP();
905 }
906
907 static void
908 wcon_do_color(TERMINAL_CONTROL_BLOCK * TCB,
909               int old_pair GCC_UNUSED,
910               int pair GCC_UNUSED,
911               int reverse GCC_UNUSED,
912               int (*outc) (SCREEN *, int) GCC_UNUSED
913 )
914 {
915     SCREEN *sp;
916
917     AssertTCB();
918     SetSP();
919 }
920
921 static void
922 wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
923 {
924     SCREEN *sp;
925
926     if (validateConsoleHandle()) {
927         SetSP();
928
929         sp->_mouse_type = M_TERM_DRIVER;
930     }
931 }
932
933 static int
934 wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB,
935                int delay
936                EVENTLIST_2nd(_nc_eventlist * evl))
937 {
938     int rc = 0;
939     SCREEN *sp;
940
941     if (validateConsoleHandle()) {
942         SetSP();
943
944         if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
945             rc = TW_MOUSE;
946         } else {
947             rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
948                                           TWAIT_MASK,
949                                           delay,
950                                           (int *) 0
951                                           EVENTLIST_2nd(evl));
952         }
953     }
954
955     return rc;
956 }
957
958 static int
959 wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
960            int yold GCC_UNUSED, int xold GCC_UNUSED,
961            int y, int x)
962 {
963     int ret = ERR;
964     if (validateConsoleHandle()) {
965         COORD loc;
966         loc.X = (short) x;
967         loc.Y = (short) (y + AdjustY());
968         SetConsoleCursorPosition(WINCONSOLE.hdl, loc);
969         ret = OK;
970     }
971     return ret;
972 }
973
974 static void
975 wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
976              int labnum GCC_UNUSED,
977              char *text GCC_UNUSED)
978 {
979     SCREEN *sp;
980
981     AssertTCB();
982     SetSP();
983 }
984
985 static void
986 wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
987                   int OnFlag GCC_UNUSED)
988 {
989     SCREEN *sp;
990
991     AssertTCB();
992     SetSP();
993 }
994
995 static chtype
996 wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
997 {
998     chtype res = A_NORMAL;
999     res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
1000     return res;
1001 }
1002
1003 static void
1004 wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
1005 {
1006     SCREEN *sp;
1007
1008     AssertTCB();
1009     SetSP();
1010 }
1011
1012 static void
1013 wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB,
1014              chtype *real_map GCC_UNUSED,
1015              chtype *fake_map GCC_UNUSED)
1016 {
1017 #define DATA(a,b) { a, b }
1018     static struct {
1019         int acs_code;
1020         int use_code;
1021     } table[] = {
1022         DATA('a', 0xb1),        /* ACS_CKBOARD  */
1023             DATA('f', 0xf8),    /* ACS_DEGREE   */
1024             DATA('g', 0xf1),    /* ACS_PLMINUS  */
1025             DATA('j', 0xd9),    /* ACS_LRCORNER */
1026             DATA('l', 0xda),    /* ACS_ULCORNER */
1027             DATA('k', 0xbf),    /* ACS_URCORNER */
1028             DATA('m', 0xc0),    /* ACS_LLCORNER */
1029             DATA('n', 0xc5),    /* ACS_PLUS     */
1030             DATA('q', 0xc4),    /* ACS_HLINE    */
1031             DATA('t', 0xc3),    /* ACS_LTEE     */
1032             DATA('u', 0xb4),    /* ACS_RTEE     */
1033             DATA('v', 0xc1),    /* ACS_BTEE     */
1034             DATA('w', 0xc2),    /* ACS_TTEE     */
1035             DATA('x', 0xb3),    /* ACS_VLINE    */
1036             DATA('y', 0xf3),    /* ACS_LEQUAL   */
1037             DATA('z', 0xf2),    /* ACS_GEQUAL   */
1038             DATA('0', 0xdb),    /* ACS_BLOCK    */
1039             DATA('{', 0xe3),    /* ACS_PI       */
1040             DATA('}', 0x9c),    /* ACS_STERLING */
1041             DATA(',', 0xae),    /* ACS_LARROW   */
1042             DATA('+', 0xaf),    /* ACS_RARROW   */
1043             DATA('~', 0xf9),    /* ACS_BULLET   */
1044     };
1045 #undef DATA
1046     unsigned n;
1047
1048     SCREEN *sp;
1049     if (validateConsoleHandle()) {
1050         SetSP();
1051
1052         for (n = 0; n < SIZEOF(table); ++n) {
1053             real_map[table[n].acs_code] =
1054                 (chtype) table[n].use_code | A_ALTCHARSET;
1055             if (sp != 0)
1056                 sp->_screen_acs_map[table[n].acs_code] = TRUE;
1057         }
1058     }
1059 }
1060
1061 static int
1062 wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,
1063            int mode,
1064            int milliseconds,
1065            int *timeleft
1066            EVENTLIST_2nd(_nc_eventlist * evl))
1067 {
1068     SCREEN *sp;
1069     int code = 0;
1070
1071     if (validateConsoleHandle()) {
1072         SetSP();
1073
1074         code = _nc_console_twait(sp,
1075                                  WINCONSOLE.inp,
1076                                  mode,
1077                                  milliseconds,
1078                                  timeleft EVENTLIST_2nd(evl));
1079     }
1080     return code;
1081 }
1082
1083 static int
1084 wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
1085 {
1086     SCREEN *sp;
1087     int n = -1;
1088
1089     T((T_CALLED("win32con::wcon_read(%p)"), TCB));
1090
1091     assert(buf);
1092     if (validateConsoleHandle()) {
1093         SetSP();
1094
1095         n = _nc_console_read(sp, WINCONSOLE.inp, buf);
1096     }
1097     returnCode(n);
1098 }
1099
1100 static int
1101 wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
1102 {
1103     T((T_CALLED("win32con::wcon_nap(%p, %d)"), TCB, ms));
1104     Sleep((DWORD) ms);
1105     returnCode(OK);
1106 }
1107
1108 static int
1109 wcon_cursorSet(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int mode)
1110 {
1111     int res = -1;
1112
1113     T((T_CALLED("win32con:wcon_cursorSet(%d)"), mode));
1114     if (validateConsoleHandle()) {
1115         CONSOLE_CURSOR_INFO this_CI = WINCONSOLE.save_CI;
1116         switch (mode) {
1117         case 0:
1118             this_CI.bVisible = FALSE;
1119             break;
1120         case 1:
1121             break;
1122         case 2:
1123             this_CI.dwSize = 100;
1124             break;
1125         }
1126         SetConsoleCursorInfo(WINCONSOLE.hdl, &this_CI);
1127     }
1128     returnCode(res);
1129 }
1130
1131 static bool
1132 wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode)
1133 {
1134     bool found = FALSE;
1135
1136     T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode));
1137     found = _nc_console_keyExist(keycode);
1138     returnBool(found);
1139 }
1140
1141 static int
1142 wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
1143 {
1144     SCREEN *sp;
1145     int code = ERR;
1146
1147     T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag));
1148
1149     if (validateConsoleHandle()) {
1150         SetSP();
1151
1152         if (sp) {
1153             code = OK;
1154         }
1155     }
1156     returnCode(code);
1157 }
1158
1159 static int
1160 wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB,
1161            int keycode,
1162            int flag)
1163 {
1164     int code = ERR;
1165     SCREEN *sp;
1166
1167     T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag));
1168
1169     if (validateConsoleHandle()) {
1170         SetSP();
1171         if (sp) {
1172             code = _nc_console_keyok(keycode, flag);
1173         }
1174     }
1175     returnCode(code);
1176 }
1177
1178 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
1179     FALSE,
1180         wcon_name,              /* Name          */
1181         wcon_CanHandle,         /* CanHandle     */
1182         wcon_init,              /* init          */
1183         wcon_release,           /* release       */
1184         wcon_size,              /* size          */
1185         wcon_sgmode,            /* sgmode        */
1186         wcon_conattr,           /* conattr       */
1187         wcon_mvcur,             /* hwcur         */
1188         wcon_mode,              /* mode          */
1189         wcon_rescol,            /* rescol        */
1190         wcon_rescolors,         /* rescolors     */
1191         wcon_setcolor,          /* color         */
1192         wcon_dobeepflash,       /* DoBeepFlash   */
1193         wcon_initpair,          /* initpair      */
1194         wcon_initcolor,         /* initcolor     */
1195         wcon_do_color,          /* docolor       */
1196         wcon_initmouse,         /* initmouse     */
1197         wcon_testmouse,         /* testmouse     */
1198         wcon_setfilter,         /* setfilter     */
1199         wcon_hwlabel,           /* hwlabel       */
1200         wcon_hwlabelOnOff,      /* hwlabelOnOff  */
1201         wcon_doupdate,          /* update        */
1202         wcon_defaultcolors,     /* defaultcolors */
1203         wcon_print,             /* print         */
1204         wcon_size,              /* getsize       */
1205         wcon_setsize,           /* setsize       */
1206         wcon_initacs,           /* initacs       */
1207         wcon_screen_init,       /* scinit        */
1208         wcon_wrap,              /* scexit        */
1209         wcon_twait,             /* twait         */
1210         wcon_read,              /* read          */
1211         wcon_nap,               /* nap           */
1212         wcon_kpad,              /* kpad          */
1213         wcon_keyok,             /* kyOk          */
1214         wcon_kyExist,           /* kyExist       */
1215         wcon_cursorSet          /* cursorSet     */
1216 };
1217
1218 #endif /* _NC_WINDOWS */