pdcurses/pdcscrn.c

changeset 97
2d43f05b284c
equal deleted inserted replaced
96:5314ebdcb38d 97:2d43f05b284c
1 /* Public Domain Curses */
2
3 #include "pdcwin.h"
4
5 RCSID("$Id: pdcscrn.c,v 1.92 2008/07/20 20:12:04 wmcbrine Exp $")
6
7 #ifdef CHTYPE_LONG
8 # define PDC_OFFSET 32
9 #else
10 # define PDC_OFFSET 8
11 #endif
12
13 /* COLOR_PAIR to attribute encoding table. */
14
15 unsigned char *pdc_atrtab = (unsigned char *)NULL;
16
17 HANDLE pdc_con_out = INVALID_HANDLE_VALUE;
18 HANDLE pdc_con_in = INVALID_HANDLE_VALUE;
19
20 DWORD pdc_quick_edit;
21
22 static short curstoreal[16], realtocurs[16] =
23 {
24 COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, COLOR_RED,
25 COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE, COLOR_BLACK + 8,
26 COLOR_BLUE + 8, COLOR_GREEN + 8, COLOR_CYAN + 8, COLOR_RED + 8,
27 COLOR_MAGENTA + 8, COLOR_YELLOW + 8, COLOR_WHITE + 8
28 };
29
30 enum { PDC_RESTORE_NONE, PDC_RESTORE_BUFFER, PDC_RESTORE_WINDOW };
31
32 /* Struct for storing console registry keys, and for use with the
33 undocumented WM_SETCONSOLEINFO message. Originally by James Brown,
34 www.catch22.net. */
35
36 static struct
37 {
38 ULONG Length;
39 COORD ScreenBufferSize;
40 COORD WindowSize;
41 ULONG WindowPosX;
42 ULONG WindowPosY;
43
44 COORD FontSize;
45 ULONG FontFamily;
46 ULONG FontWeight;
47 WCHAR FaceName[32];
48
49 ULONG CursorSize;
50 ULONG FullScreen;
51 ULONG QuickEdit;
52 ULONG AutoPosition;
53 ULONG InsertMode;
54
55 USHORT ScreenColors;
56 USHORT PopupColors;
57 ULONG HistoryNoDup;
58 ULONG HistoryBufferSize;
59 ULONG NumberOfHistoryBuffers;
60
61 COLORREF ColorTable[16];
62
63 ULONG CodePage;
64 HWND Hwnd;
65
66 WCHAR ConsoleTitle[0x100];
67 } console_info;
68
69 static CONSOLE_SCREEN_BUFFER_INFO orig_scr;
70
71 static CHAR_INFO *ci_save = NULL;
72 static DWORD old_console_mode = 0;
73
74 static bool is_nt;
75
76 static HWND _find_console_handle(void)
77 {
78 TCHAR orgtitle[1024], temptitle[1024];
79 HWND wnd;
80
81 GetConsoleTitle(orgtitle, 1024);
82
83 wsprintf(temptitle, TEXT("%d/%d"), GetTickCount(), GetCurrentProcessId());
84 SetConsoleTitle(temptitle);
85
86 Sleep(40);
87
88 wnd = FindWindow(NULL, temptitle);
89
90 SetConsoleTitle(orgtitle);
91
92 return wnd;
93 }
94
95 /* Undocumented console message */
96
97 #define WM_SETCONSOLEINFO (WM_USER + 201)
98
99 /* Wrapper around WM_SETCONSOLEINFO. We need to create the necessary
100 section (file-mapping) object in the context of the process which
101 owns the console, before posting the message. Originally by JB. */
102
103 static void _set_console_info(void)
104 {
105 CONSOLE_SCREEN_BUFFER_INFO csbi;
106 CONSOLE_CURSOR_INFO cci;
107 DWORD dwConsoleOwnerPid;
108 HANDLE hProcess;
109 HANDLE hSection, hDupSection;
110 PVOID ptrView;
111
112 /* Each-time initialization for console_info */
113
114 GetConsoleCursorInfo(pdc_con_out, &cci);
115 console_info.CursorSize = cci.dwSize;
116
117 GetConsoleScreenBufferInfo(pdc_con_out, &csbi);
118 console_info.ScreenBufferSize = csbi.dwSize;
119
120 console_info.WindowSize.X = csbi.srWindow.Right - csbi.srWindow.Left + 1;
121 console_info.WindowSize.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
122
123 console_info.WindowPosX = csbi.srWindow.Left;
124 console_info.WindowPosY = csbi.srWindow.Top;
125
126 /* Open the process which "owns" the console */
127
128 GetWindowThreadProcessId(console_info.Hwnd, &dwConsoleOwnerPid);
129
130 hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwConsoleOwnerPid);
131
132 /* Create a SECTION object backed by page-file, then map a view of
133 this section into the owner process so we can write the contents
134 of the CONSOLE_INFO buffer into it */
135
136 hSection = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE,
137 0, sizeof(console_info), 0);
138
139 /* Copy our console structure into the section-object */
140
141 ptrView = MapViewOfFile(hSection, FILE_MAP_WRITE|FILE_MAP_READ,
142 0, 0, sizeof(console_info));
143
144 memcpy(ptrView, &console_info, sizeof(console_info));
145
146 UnmapViewOfFile(ptrView);
147
148 /* Map the memory into owner process */
149
150 DuplicateHandle(GetCurrentProcess(), hSection, hProcess, &hDupSection,
151 0, FALSE, DUPLICATE_SAME_ACCESS);
152
153 /* Send console window the "update" message */
154
155 SendMessage(console_info.Hwnd, WM_SETCONSOLEINFO, (WPARAM)hDupSection, 0);
156
157 CloseHandle(hSection);
158 CloseHandle(hProcess);
159 }
160
161 /* One-time initialization for console_info -- color table and font info
162 from the registry; other values from functions. */
163
164 static void _init_console_info(void)
165 {
166 DWORD scrnmode, len;
167 HKEY reghnd;
168 int i;
169
170 console_info.Hwnd = _find_console_handle();
171 console_info.Length = sizeof(console_info);
172
173 GetConsoleMode(pdc_con_in, &scrnmode);
174 console_info.QuickEdit = !!(scrnmode & 0x0040);
175 console_info.InsertMode = !!(scrnmode & 0x0020);
176
177 console_info.FullScreen = FALSE;
178 console_info.AutoPosition = 0x10000;
179 console_info.ScreenColors = SP->orig_back << 4 | SP->orig_fore;
180 console_info.PopupColors = 0xf5;
181
182 console_info.HistoryNoDup = FALSE;
183 console_info.HistoryBufferSize = 50;
184 console_info.NumberOfHistoryBuffers = 4;
185
186 console_info.CodePage = GetConsoleOutputCP();
187
188 RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Console"), 0,
189 KEY_QUERY_VALUE, &reghnd);
190
191 len = sizeof(DWORD);
192
193 /* Default color table */
194
195 for (i = 0; i < 16; i++)
196 {
197 char tname[13];
198
199 sprintf(tname, "ColorTable%02d", i);
200 RegQueryValueExA(reghnd, tname, NULL, NULL,
201 (LPBYTE)(&(console_info.ColorTable[i])), &len);
202 }
203
204 /* Font info */
205
206 RegQueryValueEx(reghnd, TEXT("FontSize"), NULL, NULL,
207 (LPBYTE)(&console_info.FontSize), &len);
208 RegQueryValueEx(reghnd, TEXT("FontFamily"), NULL, NULL,
209 (LPBYTE)(&console_info.FontFamily), &len);
210 RegQueryValueEx(reghnd, TEXT("FontWeight"), NULL, NULL,
211 (LPBYTE)(&console_info.FontWeight), &len);
212
213 len = sizeof(WCHAR) * 32;
214 RegQueryValueExW(reghnd, L"FaceName", NULL, NULL,
215 (LPBYTE)(console_info.FaceName), &len);
216
217 RegCloseKey(reghnd);
218 }
219
220 /* close the physical screen -- may restore the screen to its state
221 before PDC_scr_open(); miscellaneous cleanup */
222
223 void PDC_scr_close(void)
224 {
225 COORD origin;
226 SMALL_RECT rect;
227
228 PDC_LOG(("PDC_scr_close() - called\n"));
229
230 PDC_reset_shell_mode();
231
232 if (SP->_restore != PDC_RESTORE_NONE)
233 {
234 if (SP->_restore == PDC_RESTORE_WINDOW)
235 {
236 rect.Top = orig_scr.srWindow.Top;
237 rect.Left = orig_scr.srWindow.Left;
238 rect.Bottom = orig_scr.srWindow.Bottom;
239 rect.Right = orig_scr.srWindow.Right;
240 }
241 else /* PDC_RESTORE_BUFFER */
242 {
243 rect.Top = rect.Left = 0;
244 rect.Bottom = orig_scr.dwSize.Y - 1;
245 rect.Right = orig_scr.dwSize.X - 1;
246 }
247
248 origin.X = origin.Y = 0;
249
250 if (!WriteConsoleOutput(pdc_con_out, ci_save, orig_scr.dwSize,
251 origin, &rect))
252 return;
253 }
254
255 if (SP->visibility != 1)
256 curs_set(1);
257
258 /* Position cursor to the bottom left of the screen. */
259
260 PDC_gotoyx(PDC_get_buffer_rows() - 2, 0);
261 }
262
263 void PDC_scr_free(void)
264 {
265 if (SP)
266 free(SP);
267 if (pdc_atrtab)
268 free(pdc_atrtab);
269
270 pdc_atrtab = (unsigned char *)NULL;
271 }
272
273 /* open the physical screen -- allocate SP, miscellaneous intialization,
274 and may save the existing screen for later restoration */
275
276 int PDC_scr_open(int argc, char **argv)
277 {
278 COORD bufsize, origin;
279 SMALL_RECT rect;
280 const char *str;
281 CONSOLE_SCREEN_BUFFER_INFO csbi;
282 int i;
283
284 PDC_LOG(("PDC_scr_open() - called\n"));
285
286 SP = calloc(1, sizeof(SCREEN));
287 pdc_atrtab = calloc(PDC_COLOR_PAIRS * PDC_OFFSET, 1);
288
289 if (!SP || !pdc_atrtab)
290 return ERR;
291
292 for (i = 0; i < 16; i++)
293 curstoreal[realtocurs[i]] = i;
294
295 pdc_con_out = GetStdHandle(STD_OUTPUT_HANDLE);
296 pdc_con_in = GetStdHandle(STD_INPUT_HANDLE);
297
298 if (GetFileType(pdc_con_in) != FILE_TYPE_CHAR)
299 {
300 fprintf(stderr, "\nRedirection is not supported.\n");
301 exit(1);
302 }
303
304 is_nt = !(GetVersion() & 0x80000000);
305
306 GetConsoleScreenBufferInfo(pdc_con_out, &csbi);
307 GetConsoleScreenBufferInfo(pdc_con_out, &orig_scr);
308 GetConsoleMode(pdc_con_in, &old_console_mode);
309
310 /* preserve QuickEdit Mode setting for use in PDC_mouse_set() when
311 the mouse is not enabled -- other console input settings are
312 cleared */
313
314 pdc_quick_edit = old_console_mode & 0x0040;
315
316 SP->lines = (str = getenv("LINES")) ? atoi(str) : PDC_get_rows();
317 SP->cols = (str = getenv("COLS")) ? atoi(str) : PDC_get_columns();
318
319 SP->mouse_wait = PDC_CLICK_PERIOD;
320 SP->audible = TRUE;
321
322 if (SP->lines < 2 || SP->lines > csbi.dwMaximumWindowSize.Y)
323 {
324 fprintf(stderr, "LINES value must be >= 2 and <= %d: got %d\n",
325 csbi.dwMaximumWindowSize.Y, SP->lines);
326
327 return ERR;
328 }
329
330 if (SP->cols < 2 || SP->cols > csbi.dwMaximumWindowSize.X)
331 {
332 fprintf(stderr, "COLS value must be >= 2 and <= %d: got %d\n",
333 csbi.dwMaximumWindowSize.X, SP->cols);
334
335 return ERR;
336 }
337
338 SP->orig_fore = csbi.wAttributes & 0x0f;
339 SP->orig_back = (csbi.wAttributes & 0xf0) >> 4;
340
341 SP->orig_attr = TRUE;
342
343 SP->_restore = PDC_RESTORE_NONE;
344
345 if (getenv("PDC_RESTORE_SCREEN"))
346 {
347 /* Attempt to save the complete console buffer */
348
349 ci_save = malloc(orig_scr.dwSize.X * orig_scr.dwSize.Y *
350 sizeof(CHAR_INFO));
351
352 if (!ci_save)
353 {
354 PDC_LOG(("PDC_scr_open() - malloc failure (1)\n"));
355
356 return ERR;
357 }
358
359 bufsize.X = orig_scr.dwSize.X;
360 bufsize.Y = orig_scr.dwSize.Y;
361
362 origin.X = origin.Y = 0;
363
364 rect.Top = rect.Left = 0;
365 rect.Bottom = orig_scr.dwSize.Y - 1;
366 rect.Right = orig_scr.dwSize.X - 1;
367
368 if (!ReadConsoleOutput(pdc_con_out, ci_save, bufsize, origin, &rect))
369 {
370 /* We can't save the complete buffer, so try and save just
371 the displayed window */
372
373 free(ci_save);
374 ci_save = NULL;
375
376 bufsize.X = orig_scr.srWindow.Right - orig_scr.srWindow.Left + 1;
377 bufsize.Y = orig_scr.srWindow.Bottom - orig_scr.srWindow.Top + 1;
378
379 ci_save = malloc(bufsize.X * bufsize.Y * sizeof(CHAR_INFO));
380
381 if (!ci_save)
382 {
383 PDC_LOG(("PDC_scr_open() - malloc failure (2)\n"));
384
385 return ERR;
386 }
387
388 origin.X = origin.Y = 0;
389
390 rect.Top = orig_scr.srWindow.Top;
391 rect.Left = orig_scr.srWindow.Left;
392 rect.Bottom = orig_scr.srWindow.Bottom;
393 rect.Right = orig_scr.srWindow.Right;
394
395 if (!ReadConsoleOutput(pdc_con_out, ci_save, bufsize,
396 origin, &rect))
397 {
398 #ifdef PDCDEBUG
399 CHAR LastError[256];
400
401 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL,
402 GetLastError(), MAKELANGID(LANG_NEUTRAL,
403 SUBLANG_DEFAULT), LastError, 256, NULL);
404
405 PDC_LOG(("PDC_scr_open() - %s\n", LastError));
406 #endif
407 free(ci_save);
408 ci_save = NULL;
409
410 return ERR;
411 }
412
413 SP->_restore = PDC_RESTORE_WINDOW;
414 }
415 else
416 SP->_restore = PDC_RESTORE_BUFFER;
417 }
418
419 SP->_preserve = (getenv("PDC_PRESERVE_SCREEN") != NULL);
420
421 PDC_reset_prog_mode();
422
423 SP->mono = FALSE;
424
425 return OK;
426 }
427
428 /* Calls SetConsoleWindowInfo with the given parameters, but fits them
429 if a scoll bar shrinks the maximum possible value. The rectangle
430 must at least fit in a half-sized window. */
431
432 static BOOL _fit_console_window(HANDLE con_out, CONST SMALL_RECT *rect)
433 {
434 SMALL_RECT run;
435 SHORT mx, my;
436
437 if (SetConsoleWindowInfo(con_out, TRUE, rect))
438 return TRUE;
439
440 run = *rect;
441 run.Right /= 2;
442 run.Bottom /= 2;
443
444 mx = run.Right;
445 my = run.Bottom;
446
447 if (!SetConsoleWindowInfo(con_out, TRUE, &run))
448 return FALSE;
449
450 for (run.Right = rect->Right; run.Right >= mx; run.Right--)
451 if (SetConsoleWindowInfo(con_out, TRUE, &run))
452 break;
453
454 if (run.Right < mx)
455 return FALSE;
456
457 for (run.Bottom = rect->Bottom; run.Bottom >= my; run.Bottom--)
458 if (SetConsoleWindowInfo(con_out, TRUE, &run))
459 return TRUE;
460
461 return FALSE;
462 }
463
464 /* the core of resize_term() */
465
466 int PDC_resize_screen(int nlines, int ncols)
467 {
468 SMALL_RECT rect;
469 COORD size, max;
470
471 if (nlines < 2 || ncols < 2)
472 return ERR;
473
474 max = GetLargestConsoleWindowSize(pdc_con_out);
475
476 rect.Left = rect.Top = 0;
477 rect.Right = ncols - 1;
478
479 if (rect.Right > max.X)
480 rect.Right = max.X;
481
482 rect.Bottom = nlines - 1;
483
484 if (rect.Bottom > max.Y)
485 rect.Bottom = max.Y;
486
487 size.X = rect.Right + 1;
488 size.Y = rect.Bottom + 1;
489
490 _fit_console_window(pdc_con_out, &rect);
491 SetConsoleScreenBufferSize(pdc_con_out, size);
492 _fit_console_window(pdc_con_out, &rect);
493 SetConsoleScreenBufferSize(pdc_con_out, size);
494 SetConsoleActiveScreenBuffer(pdc_con_out);
495
496 return OK;
497 }
498
499 void PDC_reset_prog_mode(void)
500 {
501 PDC_LOG(("PDC_reset_prog_mode() - called.\n"));
502
503 if (is_nt)
504 {
505 COORD bufsize;
506 SMALL_RECT rect;
507
508 bufsize.X = orig_scr.srWindow.Right - orig_scr.srWindow.Left + 1;
509 bufsize.Y = orig_scr.srWindow.Bottom - orig_scr.srWindow.Top + 1;
510
511 rect.Top = rect.Left = 0;
512 rect.Bottom = bufsize.Y - 1;
513 rect.Right = bufsize.X - 1;
514
515 SetConsoleScreenBufferSize(pdc_con_out, bufsize);
516 SetConsoleWindowInfo(pdc_con_out, TRUE, &rect);
517 SetConsoleScreenBufferSize(pdc_con_out, bufsize);
518 SetConsoleActiveScreenBuffer(pdc_con_out);
519 }
520
521 PDC_mouse_set();
522 }
523
524 void PDC_reset_shell_mode(void)
525 {
526 PDC_LOG(("PDC_reset_shell_mode() - called.\n"));
527
528 if (is_nt)
529 {
530 SetConsoleScreenBufferSize(pdc_con_out, orig_scr.dwSize);
531 SetConsoleWindowInfo(pdc_con_out, TRUE, &orig_scr.srWindow);
532 SetConsoleScreenBufferSize(pdc_con_out, orig_scr.dwSize);
533 SetConsoleWindowInfo(pdc_con_out, TRUE, &orig_scr.srWindow);
534 SetConsoleActiveScreenBuffer(pdc_con_out);
535 }
536
537 SetConsoleMode(pdc_con_in, old_console_mode);
538 }
539
540 void PDC_restore_screen_mode(int i)
541 {
542 }
543
544 void PDC_save_screen_mode(int i)
545 {
546 }
547
548 void PDC_init_pair(short pair, short fg, short bg)
549 {
550 unsigned char att, temp_bg;
551 chtype i;
552
553 fg = curstoreal[fg];
554 bg = curstoreal[bg];
555
556 for (i = 0; i < PDC_OFFSET; i++)
557 {
558 att = fg | (bg << 4);
559
560 if (i & (A_REVERSE >> PDC_ATTR_SHIFT))
561 att = bg | (fg << 4);
562 if (i & (A_UNDERLINE >> PDC_ATTR_SHIFT))
563 att = 1;
564 if (i & (A_INVIS >> PDC_ATTR_SHIFT))
565 {
566 temp_bg = att >> 4;
567 att = temp_bg << 4 | temp_bg;
568 }
569 if (i & (A_BOLD >> PDC_ATTR_SHIFT))
570 att |= 8;
571 if (i & (A_BLINK >> PDC_ATTR_SHIFT))
572 att |= 128;
573
574 pdc_atrtab[pair * PDC_OFFSET + i] = att;
575 }
576 }
577
578 int PDC_pair_content(short pair, short *fg, short *bg)
579 {
580 *fg = realtocurs[pdc_atrtab[pair * PDC_OFFSET] & 0x0F];
581 *bg = realtocurs[(pdc_atrtab[pair * PDC_OFFSET] & 0xF0) >> 4];
582
583 return OK;
584 }
585
586 bool PDC_can_change_color(void)
587 {
588 return is_nt;
589 }
590
591 int PDC_color_content(short color, short *red, short *green, short *blue)
592 {
593 DWORD col;
594
595 if (!console_info.Hwnd)
596 _init_console_info();
597
598 col = console_info.ColorTable[curstoreal[color]];
599
600 *red = DIVROUND(GetRValue(col) * 1000, 255);
601 *green = DIVROUND(GetGValue(col) * 1000, 255);
602 *blue = DIVROUND(GetBValue(col) * 1000, 255);
603
604 return OK;
605 }
606
607 int PDC_init_color(short color, short red, short green, short blue)
608 {
609 if (!console_info.Hwnd)
610 _init_console_info();
611
612 console_info.ColorTable[curstoreal[color]] =
613 RGB(DIVROUND(red * 255, 1000),
614 DIVROUND(green * 255, 1000),
615 DIVROUND(blue * 255, 1000));
616
617 _set_console_info();
618
619 return OK;
620 }

mercurial