1/**************************************************************************** 2 * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. * 3 * * 4 * Permission is hereby granted, free of charge, to any person obtaining a * 5 * copy of this software and associated documentation files (the * 6 * "Software"), to deal in the Software without restriction, including * 7 * without limitation the rights to use, copy, modify, merge, publish, * 8 * distribute, distribute with modifications, sublicense, and/or sell * 9 * copies of the Software, and to permit persons to whom the Software is * 10 * furnished to do so, subject to the following conditions: * 11 * * 12 * The above copyright notice and this permission notice shall be included * 13 * in all copies or substantial portions of the Software. * 14 * * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 22 * * 23 * Except as contained in this notice, the name(s) of the above copyright * 24 * holders shall not be used in advertising or otherwise to promote the * 25 * sale, use or other dealings in this Software without prior written * 26 * authorization. * 27 ****************************************************************************/ 28/**************************************************************************** 29 30NAME 31 ncurses.c --- ncurses library exerciser 32 33SYNOPSIS 34 ncurses 35 36DESCRIPTION 37 An interactive test module for the ncurses library. 38 39AUTHOR 40 Author: Eric S. Raymond <esr@snark.thyrsus.com> 1993 41 Thomas E. Dickey (beginning revision 1.27 in 1996). 42 43$Id: ncurses.c,v 1.329 2008/09/27 14:34:58 tom Exp $ 44 45***************************************************************************/ 46 47#include <test.priv.h> 48 49#ifdef __hpux 50#undef mvwdelch /* HPUX 11.23 macro will not compile */ 51#endif 52 53#if HAVE_GETTIMEOFDAY 54#if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT 55#include <sys/time.h> 56#endif 57#if HAVE_SYS_SELECT_H 58#include <sys/select.h> 59#endif 60#endif 61 62#if USE_LIBPANEL 63#include <panel.h> 64#endif 65 66#if USE_LIBMENU 67#include <menu.h> 68#endif 69 70#if USE_LIBFORM 71#include <form.h> 72#endif 73 74#ifdef NCURSES_VERSION 75 76#define NCURSES_CONST_PARAM const void 77 78#ifdef TRACE 79static unsigned save_trace = TRACE_ORDINARY | TRACE_ICALLS | TRACE_CALLS; 80extern unsigned _nc_tracing; 81#endif 82 83#else 84 85#define NCURSES_CONST_PARAM char 86 87#define mmask_t chtype /* not specified in XSI */ 88 89#ifndef ACS_S3 90#ifdef CURSES_ACS_ARRAY 91#define ACS_S3 (CURSES_ACS_ARRAY['p']) /* scan line 3 */ 92#define ACS_S7 (CURSES_ACS_ARRAY['r']) /* scan line 7 */ 93#define ACS_LEQUAL (CURSES_ACS_ARRAY['y']) /* less/equal */ 94#define ACS_GEQUAL (CURSES_ACS_ARRAY['z']) /* greater/equal */ 95#define ACS_PI (CURSES_ACS_ARRAY['{']) /* Pi */ 96#define ACS_NEQUAL (CURSES_ACS_ARRAY['|']) /* not equal */ 97#define ACS_STERLING (CURSES_ACS_ARRAY['}']) /* UK pound sign */ 98#else 99#define ACS_S3 (A_ALTCHARSET + 'p') /* scan line 3 */ 100#define ACS_S7 (A_ALTCHARSET + 'r') /* scan line 7 */ 101#define ACS_LEQUAL (A_ALTCHARSET + 'y') /* less/equal */ 102#define ACS_GEQUAL (A_ALTCHARSET + 'z') /* greater/equal */ 103#define ACS_PI (A_ALTCHARSET + '{') /* Pi */ 104#define ACS_NEQUAL (A_ALTCHARSET + '|') /* not equal */ 105#define ACS_STERLING (A_ALTCHARSET + '}') /* UK pound sign */ 106#endif 107#endif /* ACS_S3 */ 108 109#ifdef CURSES_WACS_ARRAY 110#define WACS_S3 (&(CURSES_WACS_ARRAY['p'])) /* scan line 3 */ 111#define WACS_S7 (&(CURSES_WACS_ARRAY['r'])) /* scan line 7 */ 112#define WACS_LEQUAL (&(CURSES_WACS_ARRAY['y'])) /* less/equal */ 113#define WACS_GEQUAL (&(CURSES_WACS_ARRAY['z'])) /* greater/equal */ 114#define WACS_PI (&(CURSES_WACS_ARRAY['{'])) /* Pi */ 115#define WACS_NEQUAL (&(CURSES_WACS_ARRAY['|'])) /* not equal */ 116#define WACS_STERLING (&(CURSES_WACS_ARRAY['}'])) /* UK pound sign */ 117#endif 118 119#endif 120 121#if HAVE_WCSRTOMBS 122#define count_wchars(src, len, state) wcsrtombs(0, &src, len, state) 123#define trans_wchars(dst, src, len, state) wcsrtombs(dst, &src, len, state) 124#define reset_wchars(state) memset(&state, 0, sizeof(state)) 125#elif HAVE_WCSTOMBS && HAVE_MBTOWC && HAVE_MBLEN 126#define count_wchars(src, len, state) wcstombs(0, src, len) 127#define trans_wchars(dst, src, len, state) wcstombs(dst, src, len) 128#define reset_wchars(state) mblen(NULL, 0), mbtowc(NULL, NULL, 0) 129#define state_unused 130#endif 131 132#if HAVE_MBSRTOWCS 133#define count_mbytes(src, len, state) mbsrtowcs(0, &src, len, state) 134#define trans_mbytes(dst, src, len, state) mbsrtowcs(dst, &src, len, state) 135#define reset_mbytes(state) memset(&state, 0, sizeof(state)) 136#elif HAVE_MBSTOWCS && HAVE_MBTOWC && HAVE_MBLEN 137#define count_mbytes(src, len, state) mbstowcs(0, src, len) 138#define trans_mbytes(dst, src, len, state) mbstowcs(dst, src, len) 139#define reset_mbytes(state) mblen(NULL, 0), mbtowc(NULL, NULL, 0) 140#define state_unused 141#endif 142 143#define ToggleAcs(temp,real) temp = ((temp == real) ? 0 : real) 144 145#define P(string) printw("%s\n", string) 146 147#define BLANK ' ' /* this is the background character */ 148 149#undef max_colors 150static int max_colors; /* the actual number of colors we'll use */ 151static int min_colors; /* the minimum color code */ 152static bool use_colors; /* true if we use colors */ 153 154#undef max_pairs 155static int max_pairs; /* ...and the number of color pairs */ 156 157typedef struct { 158 short red; 159 short green; 160 short blue; 161} RGB_DATA; 162 163static RGB_DATA *all_colors; 164 165static void main_menu(bool); 166 167/* The behavior of mvhline, mvvline for negative/zero length is unspecified, 168 * though we can rely on negative x/y values to stop the macro. 169 */ 170static void 171do_h_line(int y, int x, chtype c, int to) 172{ 173 if ((to) > (x)) 174 mvhline(y, x, c, (to) - (x)); 175} 176 177static void 178do_v_line(int y, int x, chtype c, int to) 179{ 180 if ((to) > (y)) 181 mvvline(y, x, c, (to) - (y)); 182} 183 184static void 185Repaint(void) 186{ 187 touchwin(stdscr); 188 touchwin(curscr); 189 wrefresh(curscr); 190} 191 192static bool 193isQuit(int c) 194{ 195 return ((c) == QUIT || (c) == ESCAPE); 196} 197#define case_QUIT QUIT: case ESCAPE 198 199/* Common function to allow ^T to toggle trace-mode in the middle of a test 200 * so that trace-files can be made smaller. 201 */ 202static int 203wGetchar(WINDOW *win) 204{ 205 int c; 206#ifdef TRACE 207 while ((c = wgetch(win)) == CTRL('T')) { 208 if (_nc_tracing) { 209 save_trace = _nc_tracing; 210 Trace(("TOGGLE-TRACING OFF")); 211 _nc_tracing = 0; 212 } else { 213 _nc_tracing = save_trace; 214 } 215 trace(_nc_tracing); 216 if (_nc_tracing) 217 Trace(("TOGGLE-TRACING ON")); 218 } 219#else 220 c = wgetch(win); 221#endif 222 return c; 223} 224#define Getchar() wGetchar(stdscr) 225 226/* replaces wgetnstr(), since we want to be able to edit values */ 227static void 228wGetstring(WINDOW *win, char *buffer, int limit) 229{ 230 int y0, x0, x, ch; 231 bool done = FALSE; 232 233 echo(); 234 getyx(win, y0, x0); 235 wattrset(win, A_REVERSE); 236 237 x = (int) strlen(buffer); 238 while (!done) { 239 if (x > (int) strlen(buffer)) 240 x = (int) strlen(buffer); 241 wmove(win, y0, x0); 242 wprintw(win, "%-*s", limit, buffer); 243 wmove(win, y0, x0 + x); 244 switch (ch = wGetchar(win)) { 245 case '\n': 246 case KEY_ENTER: 247 done = TRUE; 248 break; 249 case CTRL('U'): 250 *buffer = '\0'; 251 break; 252 case '\b': 253 case KEY_BACKSPACE: 254 case KEY_DC: 255 if (x > 0) { 256 int j; 257 for (j = --x; (buffer[j] = buffer[j + 1]) != '\0'; ++j) { 258 ; 259 } 260 } else { 261 beep(); 262 } 263 break; 264 case KEY_LEFT: 265 if (x > 0) { 266 --x; 267 } else { 268 flash(); 269 } 270 break; 271 case KEY_RIGHT: 272 ++x; 273 break; 274 default: 275 if (!isprint(ch) || ch >= KEY_MIN) { 276 beep(); 277 } else if ((int) strlen(buffer) < limit) { 278 int j; 279 for (j = (int) strlen(buffer) + 1; j > x; --j) { 280 buffer[j] = buffer[j - 1]; 281 } 282 buffer[x++] = (char) ch; 283 } else { 284 flash(); 285 } 286 } 287 } 288 289 wattroff(win, A_REVERSE); 290 wmove(win, y0, x0); 291 noecho(); 292} 293 294#if USE_WIDEC_SUPPORT 295static wchar_t 296fullwidth_of(int ch) 297{ 298 return (ch + 0xff10 - '0'); 299} 300 301static void 302make_fullwidth_text(wchar_t *target, const char *source) 303{ 304 int ch; 305 while ((ch = *source++) != 0) { 306 *target++ = fullwidth_of(ch); 307 } 308 *target = 0; 309} 310 311static void 312make_narrow_text(wchar_t *target, const char *source) 313{ 314 int ch; 315 while ((ch = *source++) != 0) { 316 *target++ = ch; 317 } 318 *target = 0; 319} 320 321static void 322make_fullwidth_digit(cchar_t *target, int digit) 323{ 324 wchar_t source[2]; 325 326 source[0] = fullwidth_of(digit + '0'); 327 source[1] = 0; 328 setcchar(target, source, A_NORMAL, 0, 0); 329} 330 331static int 332wGet_wchar(WINDOW *win, wint_t *result) 333{ 334 int c; 335#ifdef TRACE 336 while ((c = wget_wch(win, result)) == CTRL('T')) { 337 if (_nc_tracing) { 338 save_trace = _nc_tracing; 339 Trace(("TOGGLE-TRACING OFF")); 340 _nc_tracing = 0; 341 } else { 342 _nc_tracing = save_trace; 343 } 344 trace(_nc_tracing); 345 if (_nc_tracing) 346 Trace(("TOGGLE-TRACING ON")); 347 } 348#else 349 c = wget_wch(win, result); 350#endif 351 return c; 352} 353#define Get_wchar(result) wGet_wchar(stdscr, result) 354 355/* replaces wgetn_wstr(), since we want to be able to edit values */ 356static void 357wGet_wstring(WINDOW *win, wchar_t *buffer, int limit) 358{ 359 int y0, x0, x; 360 wint_t ch; 361 bool done = FALSE; 362 bool fkey = FALSE; 363 364 echo(); 365 getyx(win, y0, x0); 366 wattrset(win, A_REVERSE); 367 368 x = (int) wcslen(buffer); 369 while (!done) { 370 if (x > (int) wcslen(buffer)) 371 x = (int) wcslen(buffer); 372 373 /* clear the "window' */ 374 wmove(win, y0, x0); 375 wprintw(win, "%*s", limit, " "); 376 377 /* write the existing buffer contents */ 378 wmove(win, y0, x0); 379 waddnwstr(win, buffer, limit); 380 381 /* positions the cursor past character 'x' */ 382 wmove(win, y0, x0); 383 waddnwstr(win, buffer, x); 384 385 switch (wGet_wchar(win, &ch)) { 386 case KEY_CODE_YES: 387 fkey = TRUE; 388 switch (ch) { 389 case KEY_ENTER: 390 ch = '\n'; 391 fkey = FALSE; 392 break; 393 case KEY_BACKSPACE: 394 case KEY_DC: 395 ch = '\b'; 396 fkey = FALSE; 397 break; 398 case KEY_LEFT: 399 case KEY_RIGHT: 400 break; 401 default: 402 ch = (wint_t) -1; 403 break; 404 } 405 break; 406 case OK: 407 fkey = FALSE; 408 break; 409 default: 410 ch = (wint_t) -1; 411 fkey = TRUE; 412 break; 413 } 414 415 switch (ch) { 416 case '\n': 417 done = TRUE; 418 break; 419 case CTRL('U'): 420 *buffer = '\0'; 421 break; 422 case '\b': 423 if (x > 0) { 424 int j; 425 for (j = --x; (buffer[j] = buffer[j + 1]) != '\0'; ++j) { 426 ; 427 } 428 } else { 429 beep(); 430 } 431 break; 432 case KEY_LEFT: 433 if (x > 0) { 434 --x; 435 } else { 436 beep(); 437 } 438 break; 439 case KEY_RIGHT: 440 ++x; 441 break; 442 default: 443 if (fkey) { 444 beep(); 445 } else if ((int) wcslen(buffer) < limit) { 446 int j; 447 for (j = (int) wcslen(buffer) + 1; j > x; --j) { 448 buffer[j] = buffer[j - 1]; 449 } 450 buffer[x++] = (wchar_t) ch; 451 } else { 452 beep(); 453 } 454 } 455 } 456 457 wattroff(win, A_REVERSE); 458 wmove(win, y0, x0); 459 noecho(); 460} 461 462#endif 463 464static void 465Pause(void) 466{ 467 move(LINES - 1, 0); 468 addstr("Press any key to continue... "); 469 (void) Getchar(); 470} 471 472static void 473Cannot(const char *what) 474{ 475 printw("\nThis %s terminal %s\n\n", getenv("TERM"), what); 476 Pause(); 477} 478 479static void 480ShellOut(bool message) 481{ 482 if (message) 483 addstr("Shelling out..."); 484 def_prog_mode(); 485 endwin(); 486 system("sh"); 487 if (message) 488 addstr("returned from shellout.\n"); 489 refresh(); 490} 491 492#ifdef NCURSES_MOUSE_VERSION 493/* 494 * This function is the same as _tracemouse(), but we cannot count on that 495 * being available in the non-debug library. 496 */ 497static const char * 498mouse_decode(MEVENT const *ep) 499{ 500 static char buf[80 + (5 * 10) + (32 * 15)]; 501 502 (void) sprintf(buf, "id %2d at (%2d, %2d, %2d) state %4lx = {", 503 ep->id, ep->x, ep->y, ep->z, (unsigned long) ep->bstate); 504 505#define SHOW(m, s) if ((ep->bstate & m)==m) {strcat(buf,s); strcat(buf, ", ");} 506 507 SHOW(BUTTON1_RELEASED, "release-1"); 508 SHOW(BUTTON1_PRESSED, "press-1"); 509 SHOW(BUTTON1_CLICKED, "click-1"); 510 SHOW(BUTTON1_DOUBLE_CLICKED, "doubleclick-1"); 511 SHOW(BUTTON1_TRIPLE_CLICKED, "tripleclick-1"); 512#if NCURSES_MOUSE_VERSION == 1 513 SHOW(BUTTON1_RESERVED_EVENT, "reserved-1"); 514#endif 515 516 SHOW(BUTTON2_RELEASED, "release-2"); 517 SHOW(BUTTON2_PRESSED, "press-2"); 518 SHOW(BUTTON2_CLICKED, "click-2"); 519 SHOW(BUTTON2_DOUBLE_CLICKED, "doubleclick-2"); 520 SHOW(BUTTON2_TRIPLE_CLICKED, "tripleclick-2"); 521#if NCURSES_MOUSE_VERSION == 1 522 SHOW(BUTTON2_RESERVED_EVENT, "reserved-2"); 523#endif 524 525 SHOW(BUTTON3_RELEASED, "release-3"); 526 SHOW(BUTTON3_PRESSED, "press-3"); 527 SHOW(BUTTON3_CLICKED, "click-3"); 528 SHOW(BUTTON3_DOUBLE_CLICKED, "doubleclick-3"); 529 SHOW(BUTTON3_TRIPLE_CLICKED, "tripleclick-3"); 530#if NCURSES_MOUSE_VERSION == 1 531 SHOW(BUTTON3_RESERVED_EVENT, "reserved-3"); 532#endif 533 534 SHOW(BUTTON4_RELEASED, "release-4"); 535 SHOW(BUTTON4_PRESSED, "press-4"); 536 SHOW(BUTTON4_CLICKED, "click-4"); 537 SHOW(BUTTON4_DOUBLE_CLICKED, "doubleclick-4"); 538 SHOW(BUTTON4_TRIPLE_CLICKED, "tripleclick-4"); 539#if NCURSES_MOUSE_VERSION == 1 540 SHOW(BUTTON4_RESERVED_EVENT, "reserved-4"); 541#endif 542 543#if NCURSES_MOUSE_VERSION == 2 544 SHOW(BUTTON5_RELEASED, "release-5"); 545 SHOW(BUTTON5_PRESSED, "press-5"); 546 SHOW(BUTTON5_CLICKED, "click-5"); 547 SHOW(BUTTON5_DOUBLE_CLICKED, "doubleclick-5"); 548 SHOW(BUTTON5_TRIPLE_CLICKED, "tripleclick-5"); 549#endif 550 551 SHOW(BUTTON_CTRL, "ctrl"); 552 SHOW(BUTTON_SHIFT, "shift"); 553 SHOW(BUTTON_ALT, "alt"); 554 SHOW(ALL_MOUSE_EVENTS, "all-events"); 555 SHOW(REPORT_MOUSE_POSITION, "position"); 556 557#undef SHOW 558 559 if (buf[strlen(buf) - 1] == ' ') 560 buf[strlen(buf) - 2] = '\0'; 561 (void) strcat(buf, "}"); 562 return (buf); 563} 564#endif /* NCURSES_MOUSE_VERSION */ 565 566/**************************************************************************** 567 * 568 * Character input test 569 * 570 ****************************************************************************/ 571 572static void 573setup_getch(WINDOW *win, bool flags[]) 574{ 575 keypad(win, flags['k']); /* should be redundant, but for testing */ 576 meta(win, flags['m']); /* force this to a known state */ 577 if (flags['e']) 578 echo(); 579 else 580 noecho(); 581} 582 583static void 584wgetch_help(WINDOW *win, bool flags[]) 585{ 586 static const char *help[] = 587 { 588 "e -- toggle echo mode" 589 ,"g -- triggers a getstr test" 590 ,"k -- toggle keypad/literal mode" 591 ,"m -- toggle meta (7-bit/8-bit) mode" 592 ,"^q -- quit" 593 ,"s -- shell out\n" 594 ,"w -- create a new window" 595#ifdef SIGTSTP 596 ,"z -- suspend this process" 597#endif 598 }; 599 int y, x; 600 unsigned chk = ((SIZEOF(help) + 1) / 2); 601 unsigned n; 602 603 getyx(win, y, x); 604 move(0, 0); 605 printw("Type any key to see its %s value. Also:\n", 606 flags['k'] ? "keypad" : "literal"); 607 for (n = 0; n < SIZEOF(help); ++n) { 608 int row = 1 + (int) (n % chk); 609 int col = (n >= chk) ? COLS / 2 : 0; 610 int flg = ((strstr(help[n], "toggle") != 0) 611 && (flags[UChar(*help[n])] != FALSE)); 612 if (flg) 613 standout(); 614 mvprintw(row, col, "%s", help[n]); 615 if (col == 0) 616 clrtoeol(); 617 if (flg) 618 standend(); 619 } 620 wrefresh(stdscr); 621 wmove(win, y, x); 622} 623 624static void 625wgetch_wrap(WINDOW *win, int first_y) 626{ 627 int last_y = getmaxy(win) - 1; 628 int y = getcury(win) + 1; 629 630 if (y >= last_y) 631 y = first_y; 632 wmove(win, y, 0); 633 wclrtoeol(win); 634} 635 636#if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE 637typedef struct { 638 WINDOW *text; 639 WINDOW *frame; 640} WINSTACK; 641 642static WINSTACK *winstack = 0; 643static unsigned len_winstack = 0; 644 645static void 646forget_boxes(void) 647{ 648 if (winstack != 0) { 649 free(winstack); 650 } 651 winstack = 0; 652 len_winstack = 0; 653} 654 655static void 656remember_boxes(unsigned level, WINDOW *txt_win, WINDOW *box_win) 657{ 658 unsigned need = (level + 1) * 2; 659 660 assert(level < COLS); 661 662 if (winstack == 0) { 663 len_winstack = 20; 664 winstack = typeMalloc(WINSTACK, len_winstack); 665 } else if (need >= len_winstack) { 666 len_winstack = need; 667 winstack = typeRealloc(WINSTACK, len_winstack, winstack); 668 } 669 winstack[level].text = txt_win; 670 winstack[level].frame = box_win; 671} 672 673#if USE_SOFTKEYS && (NCURSES_VERSION_PATCH < 20071229) && NCURSES_EXT_FUNCS 674static void 675slk_repaint(void) 676{ 677 /* this chunk is now done in resize_term() */ 678 slk_touch(); 679 slk_clear(); 680 slk_noutrefresh(); 681} 682 683#else 684#define slk_repaint() /* nothing */ 685#endif 686 687/* 688 * For wgetch_test(), we create pairs of windows - one for a box, one for text. 689 * Resize both and paint the box in the parent. 690 */ 691static void 692resize_boxes(unsigned level, WINDOW *win) 693{ 694 unsigned n; 695 int base = 5; 696 int high = LINES - base; 697 int wide = COLS; 698 699 touchwin(stdscr); 700 wnoutrefresh(stdscr); 701 702 slk_repaint(); 703 704 for (n = 0; n < level; ++n) { 705 wresize(winstack[n].frame, high, wide); 706 wresize(winstack[n].text, high - 2, wide - 2); 707 high -= 2; 708 wide -= 2; 709 werase(winstack[n].text); 710 box(winstack[n].frame, 0, 0); 711 wnoutrefresh(winstack[n].frame); 712 wprintw(winstack[n].text, 713 "size %dx%d\n", 714 getmaxy(winstack[n].text), 715 getmaxx(winstack[n].text)); 716 wnoutrefresh(winstack[n].text); 717 if (winstack[n].text == win) 718 break; 719 } 720 doupdate(); 721} 722#else 723#define forget_boxes() /* nothing */ 724#define remember_boxes(level,text,frame) /* nothing */ 725#endif 726 727static void 728wgetch_test(unsigned level, WINDOW *win, int delay) 729{ 730 char buf[BUFSIZ]; 731 int first_y, first_x; 732 int c; 733 int incount = 0; 734 bool flags[256]; 735 bool blocking = (delay < 0); 736 737 memset(flags, FALSE, sizeof(flags)); 738 flags[UChar('k')] = (win == stdscr); 739 740 setup_getch(win, flags); 741 wtimeout(win, delay); 742 getyx(win, first_y, first_x); 743 744 wgetch_help(win, flags); 745 wsetscrreg(win, first_y, getmaxy(win) - 1); 746 scrollok(win, TRUE); 747 748 for (;;) { 749 while ((c = wGetchar(win)) == ERR) { 750 incount++; 751 if (blocking) { 752 (void) wprintw(win, "%05d: input error", incount); 753 break; 754 } else { 755 (void) wprintw(win, "%05d: input timed out", incount); 756 } 757 wgetch_wrap(win, first_y); 758 } 759 if (c == ERR && blocking) { 760 wprintw(win, "ERR"); 761 wgetch_wrap(win, first_y); 762 } else if (isQuit(c)) { 763 break; 764 } else if (c == 'e') { 765 flags[UChar('e')] = !flags[UChar('e')]; 766 setup_getch(win, flags); 767 wgetch_help(win, flags); 768 } else if (c == 'g') { 769 waddstr(win, "getstr test: "); 770 echo(); 771 wgetnstr(win, buf, sizeof(buf) - 1); 772 noecho(); 773 wprintw(win, "I saw %d characters:\n\t`%s'.", (int) strlen(buf), buf); 774 wclrtoeol(win); 775 wgetch_wrap(win, first_y); 776 } else if (c == 'k') { 777 flags[UChar('k')] = !flags[UChar('k')]; 778 setup_getch(win, flags); 779 wgetch_help(win, flags); 780 } else if (c == 'm') { 781 flags[UChar('m')] = !flags[UChar('m')]; 782 setup_getch(win, flags); 783 wgetch_help(win, flags); 784 } else if (c == 's') { 785 ShellOut(TRUE); 786 } else if (c == 'w') { 787 int high = getmaxy(win) - 1 - first_y + 1; 788 int wide = getmaxx(win) - first_x; 789 int old_y, old_x; 790 int new_y = first_y + getbegy(win); 791 int new_x = first_x + getbegx(win); 792 793 getyx(win, old_y, old_x); 794 if (high > 2 && wide > 2) { 795 WINDOW *wb = newwin(high, wide, new_y, new_x); 796 WINDOW *wi = newwin(high - 2, wide - 2, new_y + 1, new_x + 1); 797 798 box(wb, 0, 0); 799 wrefresh(wb); 800 wmove(wi, 0, 0); 801 remember_boxes(level, wi, wb); 802 wgetch_test(level + 1, wi, delay); 803 delwin(wi); 804 delwin(wb); 805 806 wgetch_help(win, flags); 807 wmove(win, old_y, old_x); 808 touchwin(win); 809 wrefresh(win); 810 doupdate(); 811 } 812#ifdef SIGTSTP 813 } else if (c == 'z') { 814 kill(getpid(), SIGTSTP); 815#endif 816 } else { 817 wprintw(win, "Key pressed: %04o ", c); 818#ifdef NCURSES_MOUSE_VERSION 819 if (c == KEY_MOUSE) { 820 int y, x; 821 MEVENT event; 822 823 getmouse(&event); 824 wprintw(win, "KEY_MOUSE, %s", mouse_decode(&event)); 825 getyx(win, y, x); 826 move(event.y, event.x); 827 addch('*'); 828 wmove(win, y, x); 829 } else 830#endif /* NCURSES_MOUSE_VERSION */ 831 if (c >= KEY_MIN) { 832#if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE 833 if (c == KEY_RESIZE) { 834 resize_boxes(level, win); 835 } 836#endif 837 (void) waddstr(win, keyname(c)); 838 } else if (c > 0x80) { 839 unsigned c2 = (unsigned) (c & 0x7f); 840 if (isprint(c2)) 841 (void) wprintw(win, "M-%c", UChar(c2)); 842 else 843 (void) wprintw(win, "M-%s", unctrl(c2)); 844 waddstr(win, " (high-half character)"); 845 } else { 846 if (isprint(c)) 847 (void) wprintw(win, "%c (ASCII printable character)", c); 848 else 849 (void) wprintw(win, "%s (ASCII control character)", 850 unctrl(UChar(c))); 851 } 852 wgetch_wrap(win, first_y); 853 } 854 } 855 856 wtimeout(win, -1); 857} 858 859static int 860begin_getch_test(void) 861{ 862 char buf[BUFSIZ]; 863 int delay; 864 865 refresh(); 866 867#ifdef NCURSES_MOUSE_VERSION 868 mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0); 869#endif 870 871 (void) printw("Delay in 10ths of a second (<CR> for blocking input)? "); 872 echo(); 873 getnstr(buf, sizeof(buf) - 1); 874 noecho(); 875 nonl(); 876 877 if (isdigit(UChar(buf[0]))) { 878 delay = atoi(buf) * 100; 879 } else { 880 delay = -1; 881 } 882 raw(); 883 move(5, 0); 884 return delay; 885} 886 887static void 888finish_getch_test(void) 889{ 890#ifdef NCURSES_MOUSE_VERSION 891 mousemask(0, (mmask_t *) 0); 892#endif 893 erase(); 894 noraw(); 895 nl(); 896 endwin(); 897} 898 899static void 900getch_test(void) 901{ 902 int delay = begin_getch_test(); 903 904 slk_restore(); 905 wgetch_test(0, stdscr, delay); 906 forget_boxes(); 907 finish_getch_test(); 908} 909 910#if USE_WIDEC_SUPPORT 911/* 912 * For wget_wch_test(), we create pairs of windows - one for a box, one for text. 913 * Resize both and paint the box in the parent. 914 */ 915#if defined(KEY_RESIZE) && HAVE_WRESIZE 916static void 917resize_wide_boxes(unsigned level, WINDOW *win) 918{ 919 unsigned n; 920 int base = 5; 921 int high = LINES - base; 922 int wide = COLS; 923 924 touchwin(stdscr); 925 wnoutrefresh(stdscr); 926 927 slk_repaint(); 928 929 for (n = 0; n < level; ++n) { 930 wresize(winstack[n].frame, high, wide); 931 wresize(winstack[n].text, high - 2, wide - 2); 932 high -= 2; 933 wide -= 2; 934 werase(winstack[n].text); 935 box_set(winstack[n].frame, 0, 0); 936 wnoutrefresh(winstack[n].frame); 937 wprintw(winstack[n].text, 938 "size %dx%d\n", 939 getmaxy(winstack[n].text), 940 getmaxx(winstack[n].text)); 941 wnoutrefresh(winstack[n].text); 942 if (winstack[n].text == win) 943 break; 944 } 945 doupdate(); 946} 947#endif /* KEY_RESIZE */ 948 949static char * 950wcstos(const wchar_t *src) 951{ 952 int need; 953 char *result = 0; 954 const wchar_t *tmp = src; 955#ifndef state_unused 956 mbstate_t state; 957#endif 958 959 reset_wchars(state); 960 if ((need = (int) count_wchars(tmp, 0, &state)) > 0) { 961 unsigned have = (unsigned) need; 962 if ((result = typeCalloc(char, have + 1)) != 0) { 963 tmp = src; 964 if (trans_wchars(result, tmp, have, &state) != have) { 965 free(result); 966 result = 0; 967 } 968 } 969 } 970 return result; 971} 972 973static void 974wget_wch_test(unsigned level, WINDOW *win, int delay) 975{ 976 wchar_t wchar_buf[BUFSIZ]; 977 wint_t wint_buf[BUFSIZ]; 978 int first_y, first_x; 979 wint_t c; 980 int incount = 0; 981 bool flags[256]; 982 bool blocking = (delay < 0); 983 int y, x, code; 984 char *temp; 985 986 memset(flags, FALSE, sizeof(flags)); 987 flags[UChar('k')] = (win == stdscr); 988 989 setup_getch(win, flags); 990 wtimeout(win, delay); 991 getyx(win, first_y, first_x); 992 993 wgetch_help(win, flags); 994 wsetscrreg(win, first_y, getmaxy(win) - 1); 995 scrollok(win, TRUE); 996 997 for (;;) { 998 while ((code = wGet_wchar(win, &c)) == ERR) { 999 incount++; 1000 if (blocking) { 1001 (void) wprintw(win, "%05d: input error", incount); 1002 break; 1003 } else { 1004 (void) wprintw(win, "%05d: input timed out", incount); 1005 } 1006 wgetch_wrap(win, first_y); 1007 } 1008 if (code == ERR && blocking) { 1009 wprintw(win, "ERR"); 1010 wgetch_wrap(win, first_y); 1011 } else if (isQuit((int) c)) { 1012 break; 1013 } else if (c == 'e') { 1014 flags[UChar('e')] = !flags[UChar('e')]; 1015 setup_getch(win, flags); 1016 wgetch_help(win, flags); 1017 } else if (c == 'g') { 1018 waddstr(win, "getstr test: "); 1019 echo(); 1020 code = wgetn_wstr(win, wint_buf, sizeof(wint_buf) - 1); 1021 noecho(); 1022 if (code == ERR) { 1023 wprintw(win, "wgetn_wstr returns an error."); 1024 } else { 1025 int n; 1026 for (n = 0; (wchar_buf[n] = (wchar_t) wint_buf[n]) != 0; ++n) { 1027 ; 1028 } 1029 if ((temp = wcstos(wchar_buf)) != 0) { 1030 wprintw(win, "I saw %d characters:\n\t`%s'.", 1031 (int) wcslen(wchar_buf), temp); 1032 free(temp); 1033 } else { 1034 wprintw(win, "I saw %d characters (cannot convert).", 1035 (int) wcslen(wchar_buf)); 1036 } 1037 } 1038 wclrtoeol(win); 1039 wgetch_wrap(win, first_y); 1040 } else if (c == 'k') { 1041 flags[UChar('k')] = !flags[UChar('k')]; 1042 setup_getch(win, flags); 1043 wgetch_help(win, flags); 1044 } else if (c == 'm') { 1045 flags[UChar('m')] = !flags[UChar('m')]; 1046 setup_getch(win, flags); 1047 wgetch_help(win, flags); 1048 } else if (c == 's') { 1049 ShellOut(TRUE); 1050 } else if (c == 'w') { 1051 int high = getmaxy(win) - 1 - first_y + 1; 1052 int wide = getmaxx(win) - first_x; 1053 int old_y, old_x; 1054 int new_y = first_y + getbegy(win); 1055 int new_x = first_x + getbegx(win); 1056 1057 getyx(win, old_y, old_x); 1058 if (high > 2 && wide > 2) { 1059 WINDOW *wb = newwin(high, wide, new_y, new_x); 1060 WINDOW *wi = newwin(high - 2, wide - 2, new_y + 1, new_x + 1); 1061 1062 box_set(wb, 0, 0); 1063 wrefresh(wb); 1064 wmove(wi, 0, 0); 1065 remember_boxes(level, wi, wb); 1066 wget_wch_test(level + 1, wi, delay); 1067 delwin(wi); 1068 delwin(wb); 1069 1070 wgetch_help(win, flags); 1071 wmove(win, old_y, old_x); 1072 touchwin(win); 1073 wrefresh(win); 1074 } 1075#ifdef SIGTSTP 1076 } else if (c == 'z') { 1077 kill(getpid(), SIGTSTP); 1078#endif 1079 } else { 1080 wprintw(win, "Key pressed: %04o ", (int) c); 1081#ifdef NCURSES_MOUSE_VERSION 1082 if (c == KEY_MOUSE) { 1083 MEVENT event; 1084 1085 getmouse(&event); 1086 wprintw(win, "KEY_MOUSE, %s", mouse_decode(&event)); 1087 getyx(win, y, x); 1088 move(event.y, event.x); 1089 addch('*'); 1090 wmove(win, y, x); 1091 } else 1092#endif /* NCURSES_MOUSE_VERSION */ 1093 if (code == KEY_CODE_YES) { 1094#if defined(KEY_RESIZE) && HAVE_WRESIZE 1095 if (c == KEY_RESIZE) { 1096 resize_wide_boxes(level, win); 1097 } 1098#endif 1099 (void) waddstr(win, key_name((wchar_t) c)); 1100 } else { 1101 if (c < 256 && iscntrl(c)) { 1102 (void) wprintw(win, "%s (control character)", unctrl(c)); 1103 } else { 1104 wchar_t c2 = (wchar_t) c; 1105 waddnwstr(win, &c2, 1); 1106 (void) wprintw(win, " = %#x (printable character)", (unsigned) c); 1107 } 1108 } 1109 wgetch_wrap(win, first_y); 1110 } 1111 } 1112 1113 wtimeout(win, -1); 1114} 1115 1116static void 1117get_wch_test(void) 1118{ 1119 int delay = begin_getch_test(); 1120 1121 slk_restore(); 1122 wget_wch_test(0, stdscr, delay); 1123 forget_boxes(); 1124 finish_getch_test(); 1125} 1126#endif 1127 1128/**************************************************************************** 1129 * 1130 * Character attributes test 1131 * 1132 ****************************************************************************/ 1133 1134#if HAVE_SETUPTERM || HAVE_TGETENT 1135#define get_ncv() TIGETNUM("ncv","NC") 1136#define get_xmc() TIGETNUM("xmc","sg") 1137#else 1138#define get_ncv() -1 1139#define get_xmc() -1 1140#endif 1141 1142#if !HAVE_TERMATTRS 1143static chtype 1144my_termattrs(void) 1145{ 1146 static int first = TRUE; 1147 static chtype result = 0; 1148 1149 if (first) { 1150#if !HAVE_TIGETSTR 1151 char buffer[4096]; 1152 char parsed[4096]; 1153 char *area_pointer = parsed; 1154 1155 tgetent(buffer, getenv("TERM")); 1156#endif 1157 1158 if (TIGETSTR("smso", "so")) 1159 result |= A_STANDOUT; 1160 if (TIGETSTR("smul", "us")) 1161 result |= A_UNDERLINE; 1162 if (TIGETSTR("rev", "mr")) 1163 result |= A_REVERSE; 1164 if (TIGETSTR("blink", "mb")) 1165 result |= A_BLINK; 1166 if (TIGETSTR("dim", "mh")) 1167 result |= A_DIM; 1168 if (TIGETSTR("bold", "md")) 1169 result |= A_BOLD; 1170 if (TIGETSTR("smacs", "ac")) 1171 result |= A_ALTCHARSET; 1172 1173 first = FALSE; 1174 } 1175 return result; 1176} 1177#define termattrs() my_termattrs() 1178#endif 1179 1180#define MAX_ATTRSTRING 31 1181#define LEN_ATTRSTRING 26 1182 1183static char attr_test_string[MAX_ATTRSTRING + 1]; 1184 1185static void 1186attr_legend(WINDOW *helpwin) 1187{ 1188 int row = 1; 1189 int col = 1; 1190 1191 mvwprintw(helpwin, row++, col, 1192 "ESC to exit."); 1193 mvwprintw(helpwin, row++, col, 1194 "^L repaints."); 1195 ++row; 1196 mvwprintw(helpwin, row++, col, 1197 "Modify the test strings:"); 1198 mvwprintw(helpwin, row++, col, 1199 " A digit sets gaps on each side of displayed attributes"); 1200 mvwprintw(helpwin, row++, col, 1201 " </> shifts the text left/right. "); 1202 ++row; 1203 mvwprintw(helpwin, row++, col, 1204 "Toggles:"); 1205 if (use_colors) { 1206 mvwprintw(helpwin, row++, col, 1207 " f/F/b/F toggle foreground/background background color"); 1208 mvwprintw(helpwin, row++, col, 1209 " t/T toggle text/background color attribute"); 1210 } 1211 mvwprintw(helpwin, row++, col, 1212 " a/A toggle ACS (alternate character set) mapping"); 1213 mvwprintw(helpwin, row++, col, 1214 " v/V toggle video attribute to combine with each line"); 1215} 1216 1217static void 1218show_color_attr(int fg, int bg, int tx) 1219{ 1220 if (use_colors) { 1221 printw(" Colors (fg %d, bg %d", fg, bg); 1222 if (tx >= 0) 1223 printw(", text %d", tx); 1224 printw("),"); 1225 } 1226} 1227 1228static bool 1229cycle_color_attr(int ch, short *fg, short *bg, short *tx) 1230{ 1231 bool error = FALSE; 1232 1233 if (use_colors) { 1234 switch (ch) { 1235 case 'f': 1236 *fg = (short) (*fg + 1); 1237 break; 1238 case 'F': 1239 *fg = (short) (*fg - 1); 1240 break; 1241 case 'b': 1242 *bg = (short) (*bg + 1); 1243 break; 1244 case 'B': 1245 *bg = (short) (*bg - 1); 1246 break; 1247 case 't': 1248 *tx = (short) (*tx + 1); 1249 break; 1250 case 'T': 1251 *tx = (short) (*tx - 1); 1252 break; 1253 default: 1254 beep(); 1255 error = TRUE; 1256 break; 1257 } 1258 if (*fg >= COLORS) 1259 *fg = (short) min_colors; 1260 if (*fg < min_colors) 1261 *fg = (short) (COLORS - 1); 1262 if (*bg >= COLORS) 1263 *bg = (short) min_colors; 1264 if (*bg < min_colors) 1265 *bg = (short) (COLORS - 1); 1266 if (*tx >= COLORS) 1267 *tx = -1; 1268 if (*tx < -1) 1269 *tx = (short) (COLORS - 1); 1270 } else { 1271 beep(); 1272 error = TRUE; 1273 } 1274 return error; 1275} 1276 1277static void 1278adjust_attr_string(int adjust) 1279{ 1280 int first = ((int) UChar(attr_test_string[0])) + adjust; 1281 int last = first + LEN_ATTRSTRING; 1282 1283 if (first >= ' ' && last <= '~') { /* 32..126 */ 1284 int j, k; 1285 for (j = 0, k = first; j < MAX_ATTRSTRING && k <= last; ++j, ++k) { 1286 attr_test_string[j] = (char) k; 1287 if (((k + 1 - first) % 5) == 0) { 1288 if (++j >= MAX_ATTRSTRING) 1289 break; 1290 attr_test_string[j] = ' '; 1291 } 1292 } 1293 while (j < MAX_ATTRSTRING) 1294 attr_test_string[j++] = ' '; 1295 attr_test_string[j] = '\0'; 1296 } else { 1297 beep(); 1298 } 1299} 1300 1301static void 1302init_attr_string(void) 1303{ 1304 attr_test_string[0] = 'a'; 1305 adjust_attr_string(0); 1306} 1307 1308static int 1309show_attr(int row, int skip, bool arrow, chtype attr, const char *name) 1310{ 1311 int ncv = get_ncv(); 1312 chtype test = attr & (chtype) (~A_ALTCHARSET); 1313 1314 if (arrow) 1315 mvprintw(row, 5, "-->"); 1316 mvprintw(row, 8, "%s mode:", name); 1317 mvprintw(row, 24, "|"); 1318 if (skip) 1319 printw("%*s", skip, " "); 1320 /* 1321 * Just for testing, write text using the alternate character set one 1322 * character at a time (to pass its rendition directly), and use the 1323 * string operation for the other attributes. 1324 */ 1325 if (attr & A_ALTCHARSET) { 1326 const char *s; 1327 chtype ch; 1328 1329 for (s = attr_test_string; *s != '\0'; ++s) { 1330 ch = UChar(*s); 1331 addch(ch | attr); 1332 } 1333 } else { 1334 attrset(attr); 1335 addstr(attr_test_string); 1336 attroff(attr); 1337 } 1338 if (skip) 1339 printw("%*s", skip, " "); 1340 printw("|"); 1341 if (test != A_NORMAL) { 1342 if (!(termattrs() & test)) { 1343 printw(" (N/A)"); 1344 } else { 1345 if (ncv > 0 && (getbkgd(stdscr) & A_COLOR)) { 1346 static const chtype table[] = 1347 { 1348 A_STANDOUT, 1349 A_UNDERLINE, 1350 A_REVERSE, 1351 A_BLINK, 1352 A_DIM, 1353 A_BOLD, 1354#ifdef A_INVIS 1355 A_INVIS, 1356#endif 1357 A_PROTECT, 1358 A_ALTCHARSET 1359 }; 1360 unsigned n; 1361 bool found = FALSE; 1362 for (n = 0; n < SIZEOF(table); n++) { 1363 if ((table[n] & attr) != 0 1364 && ((1 << n) & ncv) != 0) { 1365 found = TRUE; 1366 break; 1367 } 1368 } 1369 if (found) 1370 printw(" (NCV)"); 1371 } 1372 if ((termattrs() & test) != test) 1373 printw(" (Part)"); 1374 } 1375 } 1376 return row + 2; 1377} 1378/* *INDENT-OFF* */ 1379static const struct { 1380 chtype attr; 1381 NCURSES_CONST char * name; 1382} attrs_to_test[] = { 1383 { A_STANDOUT, "STANDOUT" }, 1384 { A_REVERSE, "REVERSE" }, 1385 { A_BOLD, "BOLD" }, 1386 { A_UNDERLINE, "UNDERLINE" }, 1387 { A_DIM, "DIM" }, 1388 { A_BLINK, "BLINK" }, 1389 { A_PROTECT, "PROTECT" }, 1390#ifdef A_INVIS 1391 { A_INVIS, "INVISIBLE" }, 1392#endif 1393 { A_NORMAL, "NORMAL" }, 1394}; 1395/* *INDENT-ON* */ 1396 1397static bool 1398attr_getc(int *skip, short *fg, short *bg, short *tx, int *ac, unsigned *kc) 1399{ 1400 bool result = TRUE; 1401 bool error = FALSE; 1402 WINDOW *helpwin; 1403 1404 do { 1405 int ch = Getchar(); 1406 1407 error = FALSE; 1408 if (ch < 256 && isdigit(ch)) { 1409 *skip = (ch - '0'); 1410 } else { 1411 switch (ch) { 1412 case CTRL('L'): 1413 Repaint(); 1414 break; 1415 case '?': 1416 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) { 1417 box(helpwin, 0, 0); 1418 attr_legend(helpwin); 1419 wGetchar(helpwin); 1420 delwin(helpwin); 1421 } 1422 break; 1423 case 'a': 1424 *ac = 0; 1425 break; 1426 case 'A': 1427 *ac = A_ALTCHARSET; 1428 break; 1429 case 'v': 1430 if (*kc == 0) 1431 *kc = SIZEOF(attrs_to_test) - 1; 1432 else 1433 *kc -= 1; 1434 break; 1435 case 'V': 1436 *kc += 1; 1437 if (*kc >= SIZEOF(attrs_to_test)) 1438 *kc = 0; 1439 break; 1440 case '<': 1441 adjust_attr_string(-1); 1442 break; 1443 case '>': 1444 adjust_attr_string(1); 1445 break; 1446 case case_QUIT: 1447 result = FALSE; 1448 break; 1449 default: 1450 error = cycle_color_attr(ch, fg, bg, tx); 1451 break; 1452 } 1453 } 1454 } while (error); 1455 return result; 1456} 1457 1458static void 1459attr_test(void) 1460/* test text attributes */ 1461{ 1462 int n; 1463 int skip = get_xmc(); 1464 short fg = COLOR_BLACK; /* color pair 0 is special */ 1465 short bg = COLOR_BLACK; 1466 short tx = -1; 1467 int ac = 0; 1468 unsigned j, k; 1469 1470 if (skip < 0) 1471 skip = 0; 1472 1473 n = skip; /* make it easy */ 1474 k = SIZEOF(attrs_to_test) - 1; 1475 init_attr_string(); 1476 1477 do { 1478 int row = 2; 1479 chtype normal = A_NORMAL | BLANK; 1480 chtype extras = (chtype) ac; 1481 1482 if (use_colors) { 1483 short pair = (short) (fg != COLOR_BLACK || bg != COLOR_BLACK); 1484 if (pair != 0) { 1485 pair = 1; 1486 if (init_pair(pair, fg, bg) == ERR) { 1487 beep(); 1488 } else { 1489 normal |= COLOR_PAIR(pair); 1490 } 1491 } 1492 if (tx >= 0) { 1493 pair = 2; 1494 if (init_pair(pair, tx, bg) == ERR) { 1495 beep(); 1496 } else { 1497 extras |= COLOR_PAIR(pair); 1498 } 1499 } 1500 } 1501 bkgd(normal); 1502 bkgdset(normal); 1503 erase(); 1504 1505 box(stdscr, 0, 0); 1506 mvaddstr(0, 20, "Character attribute test display"); 1507 1508 for (j = 0; j < SIZEOF(attrs_to_test); ++j) { 1509 bool arrow = (j == k); 1510 row = show_attr(row, n, arrow, 1511 extras | 1512 attrs_to_test[j].attr | 1513 attrs_to_test[k].attr, 1514 attrs_to_test[j].name); 1515 } 1516 1517 mvprintw(row, 8, 1518 "This terminal does %shave the magic-cookie glitch", 1519 get_xmc() > -1 ? "" : "not "); 1520 mvprintw(row + 1, 8, "Enter '?' for help."); 1521 show_color_attr(fg, bg, tx); 1522 printw(" ACS (%d)", ac != 0); 1523 1524 refresh(); 1525 } while (attr_getc(&n, &fg, &bg, &tx, &ac, &k)); 1526 1527 bkgdset(A_NORMAL | BLANK); 1528 erase(); 1529 endwin(); 1530} 1531 1532#if USE_WIDEC_SUPPORT 1533static wchar_t wide_attr_test_string[MAX_ATTRSTRING + 1]; 1534 1535static void 1536wide_adjust_attr_string(int adjust) 1537{ 1538 int first = ((int) UChar(wide_attr_test_string[0])) + adjust; 1539 int last = first + LEN_ATTRSTRING; 1540 1541 if (first >= ' ' && last <= '~') { /* 32..126 */ 1542 int j, k; 1543 for (j = 0, k = first; j < MAX_ATTRSTRING && k <= last; ++j, ++k) { 1544 wide_attr_test_string[j] = k; 1545 if (((k + 1 - first) % 5) == 0) { 1546 if (++j >= MAX_ATTRSTRING) 1547 break; 1548 wide_attr_test_string[j] = ' '; 1549 } 1550 } 1551 while (j < MAX_ATTRSTRING) 1552 wide_attr_test_string[j++] = ' '; 1553 wide_attr_test_string[j] = '\0'; 1554 } else { 1555 beep(); 1556 } 1557} 1558 1559static void 1560wide_init_attr_string(void) 1561{ 1562 wide_attr_test_string[0] = 'a'; 1563 wide_adjust_attr_string(0); 1564} 1565 1566static void 1567set_wide_background(short pair) 1568{ 1569 cchar_t normal; 1570 wchar_t blank[2]; 1571 1572 blank[0] = ' '; 1573 blank[1] = 0; 1574 setcchar(&normal, blank, A_NORMAL, pair, 0); 1575 bkgrnd(&normal); 1576 bkgrndset(&normal); 1577} 1578 1579static attr_t 1580get_wide_background(void) 1581{ 1582 attr_t result = A_NORMAL; 1583 attr_t attr; 1584 cchar_t ch; 1585 short pair; 1586 wchar_t wch[10]; 1587 1588 if (getbkgrnd(&ch) != ERR) { 1589 if (getcchar(&ch, wch, &attr, &pair, 0) != ERR) { 1590 result = attr; 1591 } 1592 } 1593 return result; 1594} 1595 1596static int 1597wide_show_attr(int row, int skip, bool arrow, chtype attr, short pair, const char *name) 1598{ 1599 int ncv = get_ncv(); 1600 chtype test = attr & ~WA_ALTCHARSET; 1601 1602 if (arrow) 1603 mvprintw(row, 5, "-->"); 1604 mvprintw(row, 8, "%s mode:", name); 1605 mvprintw(row, 24, "|"); 1606 if (skip) 1607 printw("%*s", skip, " "); 1608 1609 /* 1610 * Just for testing, write text using the alternate character set one 1611 * character at a time (to pass its rendition directly), and use the 1612 * string operation for the other attributes. 1613 */ 1614 if (attr & WA_ALTCHARSET) { 1615 const wchar_t *s; 1616 cchar_t ch; 1617 1618 for (s = wide_attr_test_string; *s != L'\0'; ++s) { 1619 wchar_t fill[2]; 1620 fill[0] = *s; 1621 fill[1] = L'\0'; 1622 setcchar(&ch, fill, attr, pair, 0); 1623 add_wch(&ch); 1624 } 1625 } else { 1626 attr_t old_attr; 1627 short old_pair; 1628 1629 attr_get(&old_attr, &old_pair, 0); 1630 attr_set(attr, pair, 0); 1631 addwstr(wide_attr_test_string); 1632 attr_set(old_attr, old_pair, 0); 1633 } 1634 if (skip) 1635 printw("%*s", skip, " "); 1636 printw("|"); 1637 if (test != A_NORMAL) { 1638 if (!(term_attrs() & test)) { 1639 printw(" (N/A)"); 1640 } else { 1641 if (ncv > 0 && (get_wide_background() & A_COLOR)) { 1642 static const attr_t table[] = 1643 { 1644 WA_STANDOUT, 1645 WA_UNDERLINE, 1646 WA_REVERSE, 1647 WA_BLINK, 1648 WA_DIM, 1649 WA_BOLD, 1650 WA_INVIS, 1651 WA_PROTECT, 1652 WA_ALTCHARSET 1653 }; 1654 unsigned n; 1655 bool found = FALSE; 1656 for (n = 0; n < SIZEOF(table); n++) { 1657 if ((table[n] & attr) != 0 1658 && ((1 << n) & ncv) != 0) { 1659 found = TRUE; 1660 break; 1661 } 1662 } 1663 if (found) 1664 printw(" (NCV)"); 1665 } 1666 if ((term_attrs() & test) != test) 1667 printw(" (Part)"); 1668 } 1669 } 1670 return row + 2; 1671} 1672 1673static bool 1674wide_attr_getc(int *skip, short *fg, short *bg, short *tx, int *ac, unsigned *kc) 1675{ 1676 bool result = TRUE; 1677 bool error = FALSE; 1678 WINDOW *helpwin; 1679 1680 do { 1681 int ch = Getchar(); 1682 1683 error = FALSE; 1684 if (ch < 256 && isdigit(ch)) { 1685 *skip = (ch - '0'); 1686 } else { 1687 switch (ch) { 1688 case CTRL('L'): 1689 Repaint(); 1690 break; 1691 case '?': 1692 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) { 1693 box_set(helpwin, 0, 0); 1694 attr_legend(helpwin); 1695 wGetchar(helpwin); 1696 delwin(helpwin); 1697 } 1698 break; 1699 case 'a': 1700 *ac = 0; 1701 break; 1702 case 'A': 1703 *ac = A_ALTCHARSET; 1704 break; 1705 case 'v': 1706 if (*kc == 0) 1707 *kc = SIZEOF(attrs_to_test) - 1; 1708 else 1709 *kc -= 1; 1710 break; 1711 case 'V': 1712 *kc += 1; 1713 if (*kc >= SIZEOF(attrs_to_test)) 1714 *kc = 0; 1715 break; 1716 case '<': 1717 wide_adjust_attr_string(-1); 1718 break; 1719 case '>': 1720 wide_adjust_attr_string(1); 1721 break; 1722 case case_QUIT: 1723 result = FALSE; 1724 break; 1725 default: 1726 error = cycle_color_attr(ch, fg, bg, tx); 1727 break; 1728 } 1729 } 1730 } while (error); 1731 return result; 1732} 1733 1734static void 1735wide_attr_test(void) 1736/* test text attributes using wide-character calls */ 1737{ 1738 int n; 1739 int skip = get_xmc(); 1740 short fg = COLOR_BLACK; /* color pair 0 is special */ 1741 short bg = COLOR_BLACK; 1742 short tx = -1; 1743 int ac = 0; 1744 unsigned j, k; 1745 1746 if (skip < 0) 1747 skip = 0; 1748 1749 n = skip; /* make it easy */ 1750 k = SIZEOF(attrs_to_test) - 1; 1751 wide_init_attr_string(); 1752 1753 do { 1754 int row = 2; 1755 short pair = 0; 1756 short extras = 0; 1757 1758 if (use_colors) { 1759 pair = (short) (fg != COLOR_BLACK || bg != COLOR_BLACK); 1760 if (pair != 0) { 1761 pair = 1; 1762 if (init_pair(pair, fg, bg) == ERR) { 1763 beep(); 1764 } 1765 } 1766 extras = pair; 1767 if (tx >= 0) { 1768 extras = 2; 1769 if (init_pair(extras, tx, bg) == ERR) { 1770 beep(); 1771 } 1772 } 1773 } 1774 set_wide_background(pair); 1775 erase(); 1776 1777 box_set(stdscr, 0, 0); 1778 mvaddstr(0, 20, "Character attribute test display"); 1779 1780 for (j = 0; j < SIZEOF(attrs_to_test); ++j) { 1781 row = wide_show_attr(row, n, j == k, 1782 ac | 1783 attrs_to_test[j].attr | 1784 attrs_to_test[k].attr, 1785 extras, 1786 attrs_to_test[j].name); 1787 } 1788 1789 mvprintw(row, 8, 1790 "This terminal does %shave the magic-cookie glitch", 1791 get_xmc() > -1 ? "" : "not "); 1792 mvprintw(row + 1, 8, "Enter '?' for help."); 1793 show_color_attr(fg, bg, tx); 1794 printw(" ACS (%d)", ac != 0); 1795 1796 refresh(); 1797 } while (wide_attr_getc(&n, &fg, &bg, &tx, &ac, &k)); 1798 1799 set_wide_background(0); 1800 erase(); 1801 endwin(); 1802} 1803#endif 1804 1805/**************************************************************************** 1806 * 1807 * Color support tests 1808 * 1809 ****************************************************************************/ 1810 1811static NCURSES_CONST char *the_color_names[] = 1812{ 1813 "black", 1814 "red", 1815 "green", 1816 "yellow", 1817 "blue", 1818 "magenta", 1819 "cyan", 1820 "white", 1821 "BLACK", 1822 "RED", 1823 "GREEN", 1824 "YELLOW", 1825 "BLUE", 1826 "MAGENTA", 1827 "CYAN", 1828 "WHITE" 1829}; 1830 1831static void 1832show_color_name(int y, int x, int color, bool wide) 1833{ 1834 if (move(y, x) != ERR) { 1835 char temp[80]; 1836 int width = 8; 1837 1838 if (wide) { 1839 sprintf(temp, "%02d", color); 1840 width = 4; 1841 } else if (color >= 8) { 1842 sprintf(temp, "[%02d]", color); 1843 } else { 1844 strcpy(temp, the_color_names[color]); 1845 } 1846 printw("%-*.*s", width, width, temp); 1847 } 1848} 1849 1850static void 1851color_legend(WINDOW *helpwin, bool wide) 1852{ 1853 int row = 1; 1854 int col = 1; 1855 1856 mvwprintw(helpwin, row++, col, 1857 "ESC to exit."); 1858 ++row; 1859 mvwprintw(helpwin, row++, col, 1860 "Use up/down arrow to scroll through the display if it is"); 1861 mvwprintw(helpwin, row++, col, 1862 "longer than one screen. Control/N and Control/P can be used"); 1863 mvwprintw(helpwin, row++, col, 1864 "in place of up/down arrow. Use pageup/pagedown to scroll a"); 1865 mvwprintw(helpwin, row++, col, 1866 "full screen; control/B and control/F can be used here."); 1867 ++row; 1868 mvwprintw(helpwin, row++, col, 1869 "Toggles:"); 1870 mvwprintw(helpwin, row++, col, 1871 " a/A toggle altcharset off/on"); 1872 mvwprintw(helpwin, row++, col, 1873 " b/B toggle bold off/on"); 1874 mvwprintw(helpwin, row++, col, 1875 " n/N toggle text/number on/off"); 1876 mvwprintw(helpwin, row++, col, 1877 " w/W toggle width between 8/16 colors"); 1878#if USE_WIDEC_SUPPORT 1879 if (wide) { 1880 mvwprintw(helpwin, row++, col, 1881 "Wide characters:"); 1882 mvwprintw(helpwin, row++, col, 1883 " x/X toggle text between ASCII and wide-character"); 1884 } 1885#else 1886 (void) wide; 1887#endif 1888} 1889 1890#define set_color_test(name, value) if (name != value) { name = value; base_row = 0; } 1891 1892/* generate a color test pattern */ 1893static void 1894color_test(void) 1895{ 1896 short i; 1897 int top = 0, width; 1898 int base_row = 0; 1899 int grid_top = top + 3; 1900 int page_size = (LINES - grid_top); 1901 int pairs_max = PAIR_NUMBER(A_COLOR) + 1; 1902 int row_limit; 1903 int per_row; 1904 char numbered[80]; 1905 const char *hello; 1906 bool done = FALSE; 1907 bool opt_acsc = FALSE; 1908 bool opt_bold = FALSE; 1909 bool opt_wide = FALSE; 1910 bool opt_nums = FALSE; 1911 WINDOW *helpwin; 1912 1913 if (pairs_max > COLOR_PAIRS) 1914 pairs_max = COLOR_PAIRS; 1915 1916 while (!done) { 1917 int shown = 0; 1918 1919 /* this assumes an 80-column line */ 1920 if (opt_wide) { 1921 width = 4; 1922 hello = "Test"; 1923 per_row = (COLORS > 8) ? 16 : 8; 1924 } else { 1925 width = 8; 1926 hello = "Hello"; 1927 per_row = 8; 1928 } 1929 1930 row_limit = (pairs_max + per_row - 1) / per_row; 1931 1932 move(0, 0); 1933 (void) printw("There are %d color pairs and %d colors\n", 1934 pairs_max, COLORS); 1935 1936 clrtobot(); 1937 (void) mvprintw(top + 1, 0, 1938 "%dx%d matrix of foreground/background colors, bold *%s*\n", 1939 row_limit, 1940 per_row, 1941 opt_bold ? "on" : "off"); 1942 1943 /* show color names/numbers across the top */ 1944 for (i = 0; i < per_row; i++) 1945 show_color_name(top + 2, (i + 1) * width, i, opt_wide); 1946 1947 /* show a grid of colors, with color names/ numbers on the left */ 1948 for (i = (short) (base_row * per_row); i < pairs_max; i++) { 1949 int row = grid_top + (i / per_row) - base_row; 1950 int col = (i % per_row + 1) * width; 1951 short pair = i; 1952 1953 if (row >= 0 && move(row, col) != ERR) { 1954 short fg = (short) (i % COLORS); 1955 short bg = (short) (i / COLORS); 1956 1957 init_pair(pair, fg, bg); 1958 attron((attr_t) COLOR_PAIR(pair)); 1959 if (opt_acsc) 1960 attron((attr_t) A_ALTCHARSET); 1961 if (opt_bold) 1962 attron((attr_t) A_BOLD); 1963 1964 if (opt_nums) { 1965 sprintf(numbered, "{%02X}", i); 1966 hello = numbered; 1967 } 1968 printw("%-*.*s", width, width, hello); 1969 attrset(A_NORMAL); 1970 1971 if ((i % per_row) == 0 && (i % COLORS) == 0) { 1972 show_color_name(row, 0, i / COLORS, opt_wide); 1973 } 1974 ++shown; 1975 } else if (shown) { 1976 break; 1977 } 1978 } 1979 1980 switch (wGetchar(stdscr)) { 1981 case 'a': 1982 opt_acsc = FALSE; 1983 break; 1984 case 'A': 1985 opt_acsc = TRUE; 1986 break; 1987 case 'b': 1988 opt_bold = FALSE; 1989 break; 1990 case 'B': 1991 opt_bold = TRUE; 1992 break; 1993 case 'n': 1994 opt_nums = FALSE; 1995 break; 1996 case 'N': 1997 opt_nums = TRUE; 1998 break; 1999 case case_QUIT: 2000 done = TRUE; 2001 continue; 2002 case 'w': 2003 set_color_test(opt_wide, FALSE); 2004 break; 2005 case 'W': 2006 set_color_test(opt_wide, TRUE); 2007 break; 2008 case CTRL('p'): 2009 case KEY_UP: 2010 if (base_row <= 0) { 2011 beep(); 2012 } else { 2013 base_row -= 1; 2014 } 2015 break; 2016 case CTRL('n'): 2017 case KEY_DOWN: 2018 if (base_row + page_size >= row_limit) { 2019 beep(); 2020 } else { 2021 base_row += 1; 2022 } 2023 break; 2024 case CTRL('b'): 2025 case KEY_PREVIOUS: 2026 case KEY_PPAGE: 2027 if (base_row <= 0) { 2028 beep(); 2029 } else { 2030 base_row -= (page_size - 1); 2031 if (base_row < 0) 2032 base_row = 0; 2033 } 2034 break; 2035 case CTRL('f'): 2036 case KEY_NEXT: 2037 case KEY_NPAGE: 2038 if (base_row + page_size >= row_limit) { 2039 beep(); 2040 } else { 2041 base_row += page_size - 1; 2042 if (base_row + page_size >= row_limit) { 2043 base_row = row_limit - page_size - 1; 2044 } 2045 } 2046 break; 2047 case '?': 2048 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) { 2049 box(helpwin, 0, 0); 2050 color_legend(helpwin, FALSE); 2051 wGetchar(helpwin); 2052 delwin(helpwin); 2053 } 2054 break; 2055 default: 2056 beep(); 2057 continue; 2058 } 2059 } 2060 2061 erase(); 2062 endwin(); 2063} 2064 2065#if USE_WIDEC_SUPPORT 2066/* generate a color test pattern */ 2067static void 2068wide_color_test(void) 2069{ 2070 int c; 2071 int i; 2072 int top = 0, width; 2073 int base_row = 0; 2074 int grid_top = top + 3; 2075 int page_size = (LINES - grid_top); 2076 int pairs_max = COLOR_PAIRS; 2077 int row_limit; 2078 int per_row; 2079 char numbered[80]; 2080 const char *hello; 2081 bool done = FALSE; 2082 bool opt_acsc = FALSE; 2083 bool opt_bold = FALSE; 2084 bool opt_wide = FALSE; 2085 bool opt_nums = FALSE; 2086 bool opt_xchr = FALSE; 2087 wchar_t buffer[10]; 2088 WINDOW *helpwin; 2089 2090 while (!done) { 2091 int shown = 0; 2092 2093 /* this assumes an 80-column line */ 2094 if (opt_wide) { 2095 width = 4; 2096 hello = "Test"; 2097 per_row = (COLORS > 8) ? 16 : 8; 2098 } else { 2099 width = 8; 2100 hello = "Hello"; 2101 per_row = 8; 2102 } 2103 if (opt_xchr) { 2104 make_fullwidth_text(buffer, hello); 2105 width *= 2; 2106 per_row /= 2; 2107 } else { 2108 make_narrow_text(buffer, hello); 2109 } 2110 2111 row_limit = (pairs_max + per_row - 1) / per_row; 2112 2113 move(0, 0); 2114 (void) printw("There are %d color pairs and %d colors\n", 2115 pairs_max, COLORS); 2116 2117 clrtobot(); 2118 (void) mvprintw(top + 1, 0, 2119 "%dx%d matrix of foreground/background colors, bold *%s*\n", 2120 row_limit, 2121 per_row, 2122 opt_bold ? "on" : "off"); 2123 2124 /* show color names/numbers across the top */ 2125 for (i = 0; i < per_row; i++) 2126 show_color_name(top + 2, (i + 1) * width, i, opt_wide); 2127 2128 /* show a grid of colors, with color names/ numbers on the left */ 2129 for (i = (base_row * per_row); i < pairs_max; i++) { 2130 int row = grid_top + (i / per_row) - base_row; 2131 int col = (i % per_row + 1) * width; 2132 short pair = (short) i; 2133 2134 if (row >= 0 && move(row, col) != ERR) { 2135 init_pair(pair, (short) (i % COLORS), (short) (i / COLORS)); 2136 color_set(pair, NULL); 2137 if (opt_acsc) 2138 attr_on((attr_t) A_ALTCHARSET, NULL); 2139 if (opt_bold) 2140 attr_on((attr_t) A_BOLD, NULL); 2141 2142 if (opt_nums) { 2143 sprintf(numbered, "{%02X}", i); 2144 if (opt_xchr) { 2145 make_fullwidth_text(buffer, numbered); 2146 } else { 2147 make_narrow_text(buffer, numbered); 2148 } 2149 } 2150 addnwstr(buffer, width); 2151 attr_set(A_NORMAL, 0, NULL); 2152 2153 if ((i % per_row) == 0 && (i % COLORS) == 0) { 2154 show_color_name(row, 0, i / COLORS, opt_wide); 2155 } 2156 ++shown; 2157 } else if (shown) { 2158 break; 2159 } 2160 } 2161 2162 switch (c = wGetchar(stdscr)) { 2163 case 'a': 2164 opt_acsc = FALSE; 2165 break; 2166 case 'A': 2167 opt_acsc = TRUE; 2168 break; 2169 case 'b': 2170 opt_bold = FALSE; 2171 break; 2172 case 'B': 2173 opt_bold = TRUE; 2174 break; 2175 case 'n': 2176 opt_nums = FALSE; 2177 break; 2178 case 'N': 2179 opt_nums = TRUE; 2180 break; 2181 case case_QUIT: 2182 done = TRUE; 2183 continue; 2184 case 'w': 2185 set_color_test(opt_wide, FALSE); 2186 break; 2187 case 'W': 2188 set_color_test(opt_wide, TRUE); 2189 break; 2190 case 'x': 2191 opt_xchr = FALSE; 2192 break; 2193 case 'X': 2194 opt_xchr = TRUE; 2195 break; 2196 case CTRL('p'): 2197 case KEY_UP: 2198 if (base_row <= 0) { 2199 beep(); 2200 } else { 2201 base_row -= 1; 2202 } 2203 break; 2204 case CTRL('n'): 2205 case KEY_DOWN: 2206 if (base_row + page_size >= row_limit) { 2207 beep(); 2208 } else { 2209 base_row += 1; 2210 } 2211 break; 2212 case CTRL('b'): 2213 case KEY_PREVIOUS: 2214 case KEY_PPAGE: 2215 if (base_row <= 0) { 2216 beep(); 2217 } else { 2218 base_row -= (page_size - 1); 2219 if (base_row < 0) 2220 base_row = 0; 2221 } 2222 break; 2223 case CTRL('f'): 2224 case KEY_NEXT: 2225 case KEY_NPAGE: 2226 if (base_row + page_size >= row_limit) { 2227 beep(); 2228 } else { 2229 base_row += page_size - 1; 2230 if (base_row + page_size >= row_limit) { 2231 base_row = row_limit - page_size - 1; 2232 } 2233 } 2234 break; 2235 case '?': 2236 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) { 2237 box(helpwin, 0, 0); 2238 color_legend(helpwin, TRUE); 2239 wGetchar(helpwin); 2240 delwin(helpwin); 2241 } 2242 break; 2243 default: 2244 beep(); 2245 continue; 2246 } 2247 } 2248 2249 erase(); 2250 endwin(); 2251} 2252#endif /* USE_WIDEC_SUPPORT */ 2253 2254static void 2255change_color(short current, int field, int value, int usebase) 2256{ 2257 short red, green, blue; 2258 2259 color_content(current, &red, &green, &blue); 2260 2261 switch (field) { 2262 case 0: 2263 red = (short) (usebase ? (red + value) : value); 2264 break; 2265 case 1: 2266 green = (short) (usebase ? (green + value) : value); 2267 break; 2268 case 2: 2269 blue = (short) (usebase ? (blue + value) : value); 2270 break; 2271 } 2272 2273 if (init_color(current, red, green, blue) == ERR) 2274 beep(); 2275} 2276 2277static void 2278init_all_colors(void) 2279{ 2280 short c; 2281 2282 for (c = 0; c < COLORS; ++c) 2283 init_color(c, 2284 all_colors[c].red, 2285 all_colors[c].green, 2286 all_colors[c].blue); 2287} 2288 2289#define scaled_rgb(n) ((255 * (n)) / 1000) 2290 2291static void 2292color_edit(void) 2293/* display the color test pattern, without trying to edit colors */ 2294{ 2295 int i; 2296 int current = 0; 2297 int this_c = 0, value = 0, field = 0; 2298 int last_c; 2299 int top_color = 0; 2300 int page_size = (LINES - 6); 2301 2302 init_all_colors(); 2303 refresh(); 2304 2305 for (i = 0; i < max_colors; i++) 2306 init_pair((short) i, (short) COLOR_WHITE, (short) i); 2307 2308 mvprintw(LINES - 2, 0, "Number: %d", value); 2309 2310 do { 2311 short red, green, blue; 2312 2313 attron(A_BOLD); 2314 mvaddstr(0, 20, "Color RGB Value Editing"); 2315 attroff(A_BOLD); 2316 2317 for (i = (short) top_color; 2318 (i - top_color < page_size) 2319 && (i < max_colors); i++) { 2320 char numeric[80]; 2321 2322 sprintf(numeric, "[%d]", i); 2323 mvprintw(2 + i - top_color, 0, "%c %-8s:", 2324 (i == current ? '>' : ' '), 2325 (i < (int) SIZEOF(the_color_names) 2326 ? the_color_names[i] : numeric)); 2327 attrset(COLOR_PAIR(i)); 2328 addstr(" "); 2329 attrset(A_NORMAL); 2330 2331 color_content((short) i, &red, &green, &blue); 2332 addstr(" R = "); 2333 if (current == i && field == 0) 2334 attron(A_STANDOUT); 2335 printw("%04d", red); 2336 if (current == i && field == 0) 2337 attrset(A_NORMAL); 2338 addstr(", G = "); 2339 if (current == i && field == 1) 2340 attron(A_STANDOUT); 2341 printw("%04d", green); 2342 if (current == i && field == 1) 2343 attrset(A_NORMAL); 2344 addstr(", B = "); 2345 if (current == i && field == 2) 2346 attron(A_STANDOUT); 2347 printw("%04d", blue); 2348 if (current == i && field == 2) 2349 attrset(A_NORMAL); 2350 attrset(A_NORMAL); 2351 printw(" ( %3d %3d %3d )", 2352 scaled_rgb(red), 2353 scaled_rgb(green), 2354 scaled_rgb(blue)); 2355 } 2356 2357 mvaddstr(LINES - 3, 0, 2358 "Use up/down to select a color, left/right to change fields."); 2359 mvaddstr(LINES - 2, 0, 2360 "Modify field by typing nnn=, nnn-, or nnn+. ? for help."); 2361 2362 move(2 + current - top_color, 0); 2363 2364 last_c = this_c; 2365 this_c = Getchar(); 2366 if (this_c < 256 && isdigit(this_c) && !isdigit(last_c)) 2367 value = 0; 2368 2369 switch (this_c) { 2370 case CTRL('b'): 2371 case KEY_PPAGE: 2372 if (current > 0) 2373 current -= (page_size - 1); 2374 else 2375 beep(); 2376 break; 2377 2378 case CTRL('f'): 2379 case KEY_NPAGE: 2380 if (current < (max_colors - 1)) 2381 current += (page_size - 1); 2382 else 2383 beep(); 2384 break; 2385 2386 case CTRL('p'): 2387 case KEY_UP: 2388 current = (current == 0 ? (max_colors - 1) : current - 1); 2389 break; 2390 2391 case CTRL('n'): 2392 case KEY_DOWN: 2393 current = (current == (max_colors - 1) ? 0 : current + 1); 2394 break; 2395 2396 case KEY_RIGHT: 2397 field = (field == 2 ? 0 : field + 1); 2398 break; 2399 2400 case KEY_LEFT: 2401 field = (field == 0 ? 2 : field - 1); 2402 break; 2403 2404 case '0': 2405 case '1': 2406 case '2': 2407 case '3': 2408 case '4': 2409 case '5': 2410 case '6': 2411 case '7': 2412 case '8': 2413 case '9': 2414 value = value * 10 + (this_c - '0'); 2415 break; 2416 2417 case '+': 2418 change_color((short) current, field, value, 1); 2419 break; 2420 2421 case '-': 2422 change_color((short) current, field, -value, 1); 2423 break; 2424 2425 case '=': 2426 change_color((short) current, field, value, 0); 2427 break; 2428 2429 case '?': 2430 erase(); 2431 P(" RGB Value Editing Help"); 2432 P(""); 2433 P("You are in the RGB value editor. Use the arrow keys to select one of"); 2434 P("the fields in one of the RGB triples of the current colors; the one"); 2435 P("currently selected will be reverse-video highlighted."); 2436 P(""); 2437 P("To change a field, enter the digits of the new value; they are echoed"); 2438 P("as entered. Finish by typing `='. The change will take effect instantly."); 2439 P("To increment or decrement a value, use the same procedure, but finish"); 2440 P("with a `+' or `-'."); 2441 P(""); 2442 P("Press 'm' to invoke the top-level menu with the current color settings."); 2443 P("To quit, do ESC"); 2444 2445 Pause(); 2446 erase(); 2447 break; 2448 2449 case 'm': 2450 endwin(); 2451 main_menu(FALSE); 2452 refresh(); 2453 break; 2454 2455 case case_QUIT: 2456 break; 2457 2458 default: 2459 beep(); 2460 break; 2461 } 2462 2463 if (current < 0) 2464 current = 0; 2465 if (current >= max_colors) 2466 current = max_colors - 1; 2467 if (current < top_color) 2468 top_color = current; 2469 if (current - top_color >= page_size) 2470 top_color = current - (page_size - 1); 2471 2472 mvprintw(LINES - 1, 0, "Number: %d", value); 2473 clrtoeol(); 2474 } while 2475 (!isQuit(this_c)); 2476 2477 erase(); 2478 2479 /* 2480 * ncurses does not reset each color individually when calling endwin(). 2481 */ 2482 init_all_colors(); 2483 2484 endwin(); 2485} 2486 2487/**************************************************************************** 2488 * 2489 * Soft-key label test 2490 * 2491 ****************************************************************************/ 2492 2493#if USE_SOFTKEYS 2494 2495#define SLK_HELP 17 2496#define SLK_WORK (SLK_HELP + 3) 2497 2498static void 2499slk_help(void) 2500{ 2501 static const char *table[] = 2502 { 2503 "Available commands are:" 2504 ,"" 2505 ,"^L -- repaint this message and activate soft keys" 2506 ,"a/d -- activate/disable soft keys" 2507 ,"c -- set centered format for labels" 2508 ,"l -- set left-justified format for labels" 2509 ,"r -- set right-justified format for labels" 2510 ,"[12345678] -- set label; labels are numbered 1 through 8" 2511 ,"e -- erase stdscr (should not erase labels)" 2512 ,"s -- test scrolling of shortened screen" 2513#if HAVE_SLK_COLOR 2514 ,"F/B -- cycle through foreground/background colors" 2515#endif 2516 ,"ESC -- return to main menu" 2517 ,"" 2518 ,"Note: if activating the soft keys causes your terminal to scroll up" 2519 ,"one line, your terminal auto-scrolls when anything is written to the" 2520 ,"last screen position. The ncurses code does not yet handle this" 2521 ,"gracefully." 2522 }; 2523 unsigned j; 2524 2525 move(2, 0); 2526 for (j = 0; j < SIZEOF(table); ++j) { 2527 P(table[j]); 2528 } 2529 refresh(); 2530} 2531 2532#if HAVE_SLK_COLOR 2533static void 2534call_slk_color(short fg, short bg) 2535{ 2536 init_pair(1, bg, fg); 2537 slk_color(1); 2538 mvprintw(SLK_WORK, 0, "Colors %d/%d\n", fg, bg); 2539 clrtoeol(); 2540 refresh(); 2541} 2542#endif 2543 2544static void 2545slk_test(void) 2546/* exercise the soft keys */ 2547{ 2548 int c, fmt = 1; 2549 char buf[9]; 2550 char *s; 2551#if HAVE_SLK_COLOR 2552 short fg = COLOR_BLACK; 2553 short bg = COLOR_WHITE; 2554#endif 2555 2556 c = CTRL('l'); 2557#if HAVE_SLK_COLOR 2558 if (use_colors) { 2559 call_slk_color(fg, bg); 2560 } 2561#endif 2562 2563 do { 2564 move(0, 0); 2565 switch (c) { 2566 case CTRL('l'): 2567 erase(); 2568 attron(A_BOLD); 2569 mvaddstr(0, 20, "Soft Key Exerciser"); 2570 attroff(A_BOLD); 2571 2572 slk_help(); 2573 /* fall through */ 2574 2575 case 'a': 2576 slk_restore(); 2577 break; 2578 2579 case 'e': 2580 wclear(stdscr); 2581 break; 2582 2583 case 's': 2584 mvprintw(SLK_WORK, 0, "Press Q to stop the scrolling-test: "); 2585 while ((c = Getchar()) != 'Q' && (c != ERR)) 2586 addch((chtype) c); 2587 break; 2588 2589 case 'd': 2590 slk_clear(); 2591 break; 2592 2593 case 'l': 2594 fmt = 0; 2595 break; 2596 2597 case 'c': 2598 fmt = 1; 2599 break; 2600 2601 case 'r': 2602 fmt = 2; 2603 break; 2604 2605 case '1': 2606 case '2': 2607 case '3': 2608 case '4': 2609 case '5': 2610 case '6': 2611 case '7': 2612 case '8': 2613 (void) mvaddstr(SLK_WORK, 0, "Please enter the label value: "); 2614 strcpy(buf, ""); 2615 if ((s = slk_label(c - '0')) != 0) { 2616 strncpy(buf, s, 8); 2617 } 2618 wGetstring(stdscr, buf, 8); 2619 slk_set((c - '0'), buf, fmt); 2620 slk_refresh(); 2621 move(SLK_WORK, 0); 2622 clrtobot(); 2623 break; 2624 2625 case case_QUIT: 2626 goto done; 2627 2628#if HAVE_SLK_COLOR 2629 case 'F': 2630 if (use_colors) { 2631 fg = (short) ((fg + 1) % COLORS); 2632 call_slk_color(fg, bg); 2633 } 2634 break; 2635 case 'B': 2636 if (use_colors) { 2637 bg = (short) ((bg + 1) % COLORS); 2638 call_slk_color(fg, bg); 2639 } 2640 break; 2641#endif 2642#if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE 2643 case KEY_RESIZE: 2644 wnoutrefresh(stdscr); 2645 break; 2646#endif 2647 2648 default: 2649 beep(); 2650 } 2651 } while (!isQuit(c = Getchar())); 2652 2653 done: 2654 slk_clear(); 2655 erase(); 2656 endwin(); 2657} 2658 2659#if USE_WIDEC_SUPPORT 2660#define SLKLEN 8 2661static void 2662wide_slk_test(void) 2663/* exercise the soft keys */ 2664{ 2665 int c, fmt = 1; 2666 wchar_t buf[SLKLEN + 1]; 2667 char *s; 2668 short fg = COLOR_BLACK; 2669 short bg = COLOR_WHITE; 2670 2671 c = CTRL('l'); 2672 if (use_colors) { 2673 call_slk_color(fg, bg); 2674 } 2675 do { 2676 move(0, 0); 2677 switch (c) { 2678 case CTRL('l'): 2679 erase(); 2680 attr_on(WA_BOLD, NULL); 2681 mvaddstr(0, 20, "Soft Key Exerciser"); 2682 attr_off(WA_BOLD, NULL); 2683 2684 slk_help(); 2685 /* fall through */ 2686 2687 case 'a': 2688 slk_restore(); 2689 break; 2690 2691 case 'e': 2692 wclear(stdscr); 2693 break; 2694 2695 case 's': 2696 mvprintw(SLK_WORK, 0, "Press Q to stop the scrolling-test: "); 2697 while ((c = Getchar()) != 'Q' && (c != ERR)) 2698 addch((chtype) c); 2699 break; 2700 2701 case 'd': 2702 slk_clear(); 2703 break; 2704 2705 case 'l': 2706 fmt = 0; 2707 break; 2708 2709 case 'c': 2710 fmt = 1; 2711 break; 2712 2713 case 'r': 2714 fmt = 2; 2715 break; 2716 2717 case '1': 2718 case '2': 2719 case '3': 2720 case '4': 2721 case '5': 2722 case '6': 2723 case '7': 2724 case '8': 2725 (void) mvaddstr(SLK_WORK, 0, "Please enter the label value: "); 2726 *buf = 0; 2727 if ((s = slk_label(c - '0')) != 0) { 2728 char *temp = strdup(s); 2729 size_t used = strlen(temp); 2730 size_t want = SLKLEN; 2731 size_t test; 2732#ifndef state_unused 2733 mbstate_t state; 2734#endif 2735 2736 buf[0] = L'\0'; 2737 while (want > 0 && used != 0) { 2738 const char *base = s; 2739 reset_mbytes(state); 2740 test = count_mbytes(base, 0, &state); 2741 if (test == (size_t) -1) { 2742 temp[--used] = 0; 2743 } else if (test > want) { 2744 temp[--used] = 0; 2745 } else { 2746 reset_mbytes(state); 2747 trans_mbytes(buf, base, want, &state); 2748 break; 2749 } 2750 } 2751 free(temp); 2752 } 2753 wGet_wstring(stdscr, buf, SLKLEN); 2754 slk_wset((c - '0'), buf, fmt); 2755 slk_refresh(); 2756 move(SLK_WORK, 0); 2757 clrtobot(); 2758 break; 2759 2760 case case_QUIT: 2761 goto done; 2762 2763 case 'F': 2764 if (use_colors) { 2765 fg = (short) ((fg + 1) % COLORS); 2766 call_slk_color(fg, bg); 2767 } 2768 break; 2769 case 'B': 2770 if (use_colors) { 2771 bg = (short) ((bg + 1) % COLORS); 2772 call_slk_color(fg, bg); 2773 } 2774 break; 2775#if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE 2776 case KEY_RESIZE: 2777 wnoutrefresh(stdscr); 2778 break; 2779#endif 2780 default: 2781 beep(); 2782 } 2783 } while (!isQuit(c = Getchar())); 2784 2785 done: 2786 slk_clear(); 2787 erase(); 2788 endwin(); 2789} 2790#endif 2791#endif /* SLK_INIT */ 2792 2793/**************************************************************************** 2794 * 2795 * Alternate character-set stuff 2796 * 2797 ****************************************************************************/ 2798/* *INDENT-OFF* */ 2799static struct { 2800 chtype attr; 2801 const char *name; 2802} attrs_to_cycle[] = { 2803 { A_NORMAL, "normal" }, 2804 { A_BOLD, "bold" }, 2805 { A_REVERSE, "reverse" }, 2806 { A_UNDERLINE, "underline" }, 2807}; 2808/* *INDENT-ON* */ 2809 2810static bool 2811cycle_attr(int ch, unsigned *at_code, chtype *attr) 2812{ 2813 bool result = TRUE; 2814 2815 switch (ch) { 2816 case 'v': 2817 if ((*at_code += 1) >= SIZEOF(attrs_to_cycle)) 2818 *at_code = 0; 2819 break; 2820 case 'V': 2821 if (*at_code == 1) 2822 *at_code = SIZEOF(attrs_to_cycle) - 1; 2823 else 2824 *at_code -= 1; 2825 break; 2826 default: 2827 result = FALSE; 2828 break; 2829 } 2830 if (result) 2831 *attr = attrs_to_cycle[*at_code].attr; 2832 return result; 2833} 2834 2835static bool 2836cycle_colors(int ch, int *fg, int *bg, short *pair) 2837{ 2838 bool result = FALSE; 2839 2840 if (use_colors) { 2841 result = TRUE; 2842 switch (ch) { 2843 case 'F': 2844 if ((*fg -= 1) < 0) 2845 *fg = COLORS - 1; 2846 break; 2847 case 'f': 2848 if ((*fg += 1) >= COLORS) 2849 *fg = 0; 2850 break; 2851 case 'B': 2852 if ((*bg -= 1) < 0) 2853 *bg = COLORS - 1; 2854 break; 2855 case 'b': 2856 if ((*bg += 1) >= COLORS) 2857 *bg = 0; 2858 break; 2859 default: 2860 result = FALSE; 2861 break; 2862 } 2863 if (result) { 2864 *pair = (short) (*fg != COLOR_BLACK || *bg != COLOR_BLACK); 2865 if (*pair != 0) { 2866 *pair = 1; 2867 if (init_pair(*pair, (short) *fg, (short) *bg) == ERR) { 2868 result = FALSE; 2869 } 2870 } 2871 } 2872 } 2873 return result; 2874} 2875 2876/* ISO 6429: codes 0x80 to 0x9f may be control characters that cause the 2877 * terminal to perform functions. The remaining codes can be graphic. 2878 */ 2879static void 2880show_upper_chars(unsigned first, int repeat, attr_t attr, short pair) 2881{ 2882 bool C1 = (first == 128); 2883 unsigned code; 2884 unsigned last = first + 31; 2885 int reply; 2886 2887 erase(); 2888 attron(A_BOLD); 2889 mvprintw(0, 20, "Display of %s Character Codes %d to %d", 2890 C1 ? "C1" : "GR", first, last); 2891 attroff(A_BOLD); 2892 refresh(); 2893 2894 for (code = first; code <= last; code++) { 2895 int count = repeat; 2896 int row = 2 + ((int) (code - first) % 16); 2897 int col = ((int) (code - first) / 16) * COLS / 2; 2898 char tmp[80]; 2899 sprintf(tmp, "%3u (0x%x)", code, code); 2900 mvprintw(row, col, "%*s: ", COLS / 4, tmp); 2901 2902 do { 2903 if (C1) 2904 nodelay(stdscr, TRUE); 2905 echochar(code | attr | COLOR_PAIR(pair)); 2906 if (C1) { 2907 /* (yes, this _is_ crude) */ 2908 while ((reply = Getchar()) != ERR) { 2909 addch(UChar(reply)); 2910 napms(10); 2911 } 2912 nodelay(stdscr, FALSE); 2913 } 2914 } while (--count > 0); 2915 } 2916} 2917 2918#define PC_COLS 4 2919 2920static void 2921show_pc_chars(int repeat, attr_t attr, short pair) 2922{ 2923 unsigned code; 2924 2925 erase(); 2926 attron(A_BOLD); 2927 mvprintw(0, 20, "Display of PC Character Codes"); 2928 attroff(A_BOLD); 2929 refresh(); 2930 2931 for (code = 0; code < 16; ++code) { 2932 mvprintw(2, (int) code * PC_COLS + 8, "%X", code); 2933 } 2934 for (code = 0; code < 256; code++) { 2935 int count = repeat; 2936 int row = 3 + (int) (code / 16) + (code >= 128); 2937 int col = 8 + (int) (code % 16) * PC_COLS; 2938 if ((code % 16) == 0) 2939 mvprintw(row, 0, "0x%02x:", code); 2940 move(row, col); 2941 do { 2942 switch (code) { 2943 case '\n': 2944 case '\r': 2945 case '\b': 2946 case '\f': 2947 case '\033': 2948 case 0x9b: 2949 /* 2950 * Skip the ones that do not work. 2951 */ 2952 break; 2953 default: 2954 addch(code | A_ALTCHARSET | attr | COLOR_PAIR(pair)); 2955 break; 2956 } 2957 } while (--count > 0); 2958 } 2959} 2960 2961static void 2962show_box_chars(int repeat, attr_t attr, short pair) 2963{ 2964 (void) repeat; 2965 attr |= COLOR_PAIR(pair); 2966 2967 erase(); 2968 attron(A_BOLD); 2969 mvaddstr(0, 20, "Display of the ACS Line-Drawing Set"); 2970 attroff(A_BOLD); 2971 refresh(); 2972 box(stdscr, 0, 0); 2973 /* *INDENT-OFF* */ 2974 mvhline(LINES / 2, 0, ACS_HLINE | attr, COLS); 2975 mvvline(0, COLS / 2, ACS_VLINE | attr, LINES); 2976 mvaddch(0, COLS / 2, ACS_TTEE | attr); 2977 mvaddch(LINES / 2, COLS / 2, ACS_PLUS | attr); 2978 mvaddch(LINES - 1, COLS / 2, ACS_BTEE | attr); 2979 mvaddch(LINES / 2, 0, ACS_LTEE | attr); 2980 mvaddch(LINES / 2, COLS - 1, ACS_RTEE | attr); 2981 /* *INDENT-ON* */ 2982 2983} 2984 2985static int 2986show_1_acs(int n, int repeat, const char *name, chtype code) 2987{ 2988 const int height = 16; 2989 int row = 2 + (n % height); 2990 int col = (n / height) * COLS / 2; 2991 2992 mvprintw(row, col, "%*s : ", COLS / 4, name); 2993 do { 2994 addch(code); 2995 } while (--repeat > 0); 2996 return n + 1; 2997} 2998 2999static void 3000show_acs_chars(int repeat, attr_t attr, short pair) 3001/* display the ACS character set */ 3002{ 3003 int n; 3004 3005#define BOTH(name) #name, (name | attr | COLOR_PAIR(pair)) 3006 3007 erase(); 3008 attron(A_BOLD); 3009 mvaddstr(0, 20, "Display of the ACS Character Set"); 3010 attroff(A_BOLD); 3011 refresh(); 3012 3013 n = show_1_acs(0, repeat, BOTH(ACS_ULCORNER)); 3014 n = show_1_acs(n, repeat, BOTH(ACS_URCORNER)); 3015 n = show_1_acs(n, repeat, BOTH(ACS_LLCORNER)); 3016 n = show_1_acs(n, repeat, BOTH(ACS_LRCORNER)); 3017 3018 n = show_1_acs(n, repeat, BOTH(ACS_LTEE)); 3019 n = show_1_acs(n, repeat, BOTH(ACS_RTEE)); 3020 n = show_1_acs(n, repeat, BOTH(ACS_TTEE)); 3021 n = show_1_acs(n, repeat, BOTH(ACS_BTEE)); 3022 3023 n = show_1_acs(n, repeat, BOTH(ACS_HLINE)); 3024 n = show_1_acs(n, repeat, BOTH(ACS_VLINE)); 3025 3026 /* 3027 * HPUX's ACS definitions are broken here. Just give up. 3028 */ 3029#if !(defined(__hpux) && !defined(NCURSES_VERSION)) 3030 n = show_1_acs(n, repeat, BOTH(ACS_LARROW)); 3031 n = show_1_acs(n, repeat, BOTH(ACS_RARROW)); 3032 n = show_1_acs(n, repeat, BOTH(ACS_UARROW)); 3033 n = show_1_acs(n, repeat, BOTH(ACS_DARROW)); 3034 3035 n = show_1_acs(n, repeat, BOTH(ACS_BLOCK)); 3036 n = show_1_acs(n, repeat, BOTH(ACS_BOARD)); 3037 n = show_1_acs(n, repeat, BOTH(ACS_LANTERN)); 3038 n = show_1_acs(n, repeat, BOTH(ACS_BULLET)); 3039 n = show_1_acs(n, repeat, BOTH(ACS_CKBOARD)); 3040 n = show_1_acs(n, repeat, BOTH(ACS_DEGREE)); 3041 n = show_1_acs(n, repeat, BOTH(ACS_DIAMOND)); 3042 n = show_1_acs(n, repeat, BOTH(ACS_PLMINUS)); 3043 n = show_1_acs(n, repeat, BOTH(ACS_PLUS)); 3044 3045 n = show_1_acs(n, repeat, BOTH(ACS_GEQUAL)); 3046 n = show_1_acs(n, repeat, BOTH(ACS_NEQUAL)); 3047 n = show_1_acs(n, repeat, BOTH(ACS_LEQUAL)); 3048 3049 n = show_1_acs(n, repeat, BOTH(ACS_STERLING)); 3050 n = show_1_acs(n, repeat, BOTH(ACS_PI)); 3051 n = show_1_acs(n, repeat, BOTH(ACS_S1)); 3052 n = show_1_acs(n, repeat, BOTH(ACS_S3)); 3053 n = show_1_acs(n, repeat, BOTH(ACS_S7)); 3054 n = show_1_acs(n, repeat, BOTH(ACS_S9)); 3055#endif 3056} 3057 3058static void 3059acs_display(void) 3060{ 3061 int c = 'a'; 3062 char *term = getenv("TERM"); 3063 const char *pch_kludge = ((term != 0 && strstr(term, "linux")) 3064 ? "p=PC, " 3065 : ""); 3066 chtype attr = A_NORMAL; 3067 int digit = 0; 3068 int repeat = 1; 3069 int fg = COLOR_BLACK; 3070 int bg = COLOR_BLACK; 3071 unsigned at_code = 0; 3072 short pair = 0; 3073 void (*last_show_acs) (int, attr_t, short) = 0; 3074 3075 do { 3076 switch (c) { 3077 case CTRL('L'): 3078 Repaint(); 3079 break; 3080 case 'a': 3081 ToggleAcs(last_show_acs, show_acs_chars); 3082 break; 3083 case 'p': 3084 if (*pch_kludge) 3085 ToggleAcs(last_show_acs, show_pc_chars); 3086 else 3087 beep(); 3088 break; 3089 case 'x': 3090 ToggleAcs(last_show_acs, show_box_chars); 3091 break; 3092 case '0': 3093 case '1': 3094 case '2': 3095 case '3': 3096 digit = (c - '0'); 3097 last_show_acs = 0; 3098 break; 3099 case '-': 3100 if (digit > 0) { 3101 --digit; 3102 last_show_acs = 0; 3103 } else { 3104 beep(); 3105 } 3106 break; 3107 case '+': 3108 if (digit < 3) { 3109 ++digit; 3110 last_show_acs = 0; 3111 } else { 3112 beep(); 3113 } 3114 break; 3115 case '>': 3116 if (repeat < (COLS / 4)) 3117 ++repeat; 3118 break; 3119 case '<': 3120 if (repeat > 1) 3121 --repeat; 3122 break; 3123 default: 3124 if (cycle_attr(c, &at_code, &attr) 3125 || cycle_colors(c, &fg, &bg, &pair)) { 3126 break; 3127 } else { 3128 beep(); 3129 } 3130 break; 3131 } 3132 if (last_show_acs != 0) 3133 last_show_acs(repeat, attr, pair); 3134 else 3135 show_upper_chars((unsigned) (digit * 32 + 128), repeat, attr, pair); 3136 3137 mvprintw(LINES - 3, 0, 3138 "Note: ANSI terminals may not display C1 characters."); 3139 mvprintw(LINES - 2, 0, 3140 "Select: a=ACS, x=box, %s0=C1, 1-3,+/- non-ASCII, </> repeat, ESC=quit", 3141 pch_kludge); 3142 if (use_colors) { 3143 mvprintw(LINES - 1, 0, 3144 "v/V, f/F, b/B cycle through video attributes (%s) and color %d/%d.", 3145 attrs_to_cycle[at_code].name, 3146 fg, bg); 3147 } else { 3148 mvprintw(LINES - 1, 0, 3149 "v/V cycles through video attributes (%s).", 3150 attrs_to_cycle[at_code].name); 3151 } 3152 refresh(); 3153 } while (!isQuit(c = Getchar())); 3154 3155 Pause(); 3156 erase(); 3157 endwin(); 3158} 3159 3160#if USE_WIDEC_SUPPORT 3161static cchar_t * 3162merge_wide_attr(cchar_t *dst, const cchar_t *src, attr_t attr, short pair) 3163{ 3164 int count = getcchar(src, NULL, NULL, NULL, 0); 3165 wchar_t *wch = 0; 3166 attr_t ignore_attr; 3167 short ignore_pair; 3168 3169 *dst = *src; 3170 if (count > 0) { 3171 if ((wch = typeMalloc(wchar_t, (unsigned) count + 1)) != 0) { 3172 if (getcchar(src, wch, &ignore_attr, &ignore_pair, 0) != ERR) { 3173 attr |= (ignore_attr & A_ALTCHARSET); 3174 setcchar(dst, wch, attr, pair, 0); 3175 } 3176 free(wch); 3177 } 3178 } 3179 return dst; 3180} 3181 3182static void 3183show_upper_widechars(int first, int repeat, int space, attr_t attr, short pair) 3184{ 3185 cchar_t temp; 3186 wchar_t code; 3187 int last = first + 31; 3188 3189 erase(); 3190 attron(A_BOLD); 3191 mvprintw(0, 20, "Display of Character Codes %d to %d", first, last); 3192 attroff(A_BOLD); 3193 3194 for (code = first; (int) code <= last; code++) { 3195 int row = 2 + ((code - first) % 16); 3196 int col = ((code - first) / 16) * COLS / 2; 3197 wchar_t codes[10]; 3198 char tmp[80]; 3199 int count = repeat; 3200 int y, x; 3201 3202 memset(&codes, 0, sizeof(codes)); 3203 codes[0] = code; 3204 sprintf(tmp, "%3ld (0x%lx)", (long) code, (long) code); 3205 mvprintw(row, col, "%*s: ", COLS / 4, tmp); 3206 setcchar(&temp, codes, attr, pair, 0); 3207 do { 3208 /* 3209 * Give non-spacing characters something to combine with. If we 3210 * don't, they'll bunch up in a heap on the space after the ":". 3211 * Mark them with reverse-video to make them simpler to find on 3212 * the display. 3213 */ 3214 if (wcwidth(code) == 0) 3215 addch(space | A_REVERSE); 3216 /* 3217 * This could use add_wch(), but is done for comparison with the 3218 * normal 'f' test (and to make a test-case for echo_wchar()). 3219 * The screen will flicker because the erase() at the top of the 3220 * function is met by the builtin refresh() in echo_wchar(). 3221 */ 3222 echo_wchar(&temp); 3223 /* 3224 * The repeat-count may make text wrap - avoid that. 3225 */ 3226 getyx(stdscr, y, x); 3227 if (x >= col + (COLS / 2) - 2) 3228 break; 3229 } while (--count > 0); 3230 } 3231} 3232 3233static int 3234show_1_wacs(int n, int repeat, const char *name, const cchar_t *code) 3235{ 3236 const int height = 16; 3237 int row = 2 + (n % height); 3238 int col = (n / height) * COLS / 2; 3239 3240 mvprintw(row, col, "%*s : ", COLS / 4, name); 3241 while (repeat-- >= 0) { 3242 add_wch(code); 3243 } 3244 return n + 1; 3245} 3246 3247#define MERGE_ATTR(wch) merge_wide_attr(&temp, wch, attr, pair) 3248 3249static void 3250show_wacs_chars(int repeat, attr_t attr, short pair) 3251/* display the wide-ACS character set */ 3252{ 3253 cchar_t temp; 3254 3255 int n; 3256 3257/*#define BOTH2(name) #name, &(name) */ 3258#define BOTH2(name) #name, MERGE_ATTR(name) 3259 3260 erase(); 3261 attron(A_BOLD); 3262 mvaddstr(0, 20, "Display of the Wide-ACS Character Set"); 3263 attroff(A_BOLD); 3264 refresh(); 3265 3266 n = show_1_wacs(0, repeat, BOTH2(WACS_ULCORNER)); 3267 n = show_1_wacs(n, repeat, BOTH2(WACS_URCORNER)); 3268 n = show_1_wacs(n, repeat, BOTH2(WACS_LLCORNER)); 3269 n = show_1_wacs(n, repeat, BOTH2(WACS_LRCORNER)); 3270 3271 n = show_1_wacs(n, repeat, BOTH2(WACS_LTEE)); 3272 n = show_1_wacs(n, repeat, BOTH2(WACS_RTEE)); 3273 n = show_1_wacs(n, repeat, BOTH2(WACS_TTEE)); 3274 n = show_1_wacs(n, repeat, BOTH2(WACS_BTEE)); 3275 3276 n = show_1_wacs(n, repeat, BOTH2(WACS_HLINE)); 3277 n = show_1_wacs(n, repeat, BOTH2(WACS_VLINE)); 3278 3279 n = show_1_wacs(n, repeat, BOTH2(WACS_LARROW)); 3280 n = show_1_wacs(n, repeat, BOTH2(WACS_RARROW)); 3281 n = show_1_wacs(n, repeat, BOTH2(WACS_UARROW)); 3282 n = show_1_wacs(n, repeat, BOTH2(WACS_DARROW)); 3283 3284 n = show_1_wacs(n, repeat, BOTH2(WACS_BLOCK)); 3285 n = show_1_wacs(n, repeat, BOTH2(WACS_BOARD)); 3286 n = show_1_wacs(n, repeat, BOTH2(WACS_LANTERN)); 3287 n = show_1_wacs(n, repeat, BOTH2(WACS_BULLET)); 3288 n = show_1_wacs(n, repeat, BOTH2(WACS_CKBOARD)); 3289 n = show_1_wacs(n, repeat, BOTH2(WACS_DEGREE)); 3290 n = show_1_wacs(n, repeat, BOTH2(WACS_DIAMOND)); 3291 n = show_1_wacs(n, repeat, BOTH2(WACS_PLMINUS)); 3292 n = show_1_wacs(n, repeat, BOTH2(WACS_PLUS)); 3293 3294#ifdef CURSES_WACS_ARRAY 3295 n = show_1_wacs(n, repeat, BOTH2(WACS_GEQUAL)); 3296 n = show_1_wacs(n, repeat, BOTH2(WACS_NEQUAL)); 3297 n = show_1_wacs(n, repeat, BOTH2(WACS_LEQUAL)); 3298 3299 n = show_1_wacs(n, repeat, BOTH2(WACS_STERLING)); 3300 n = show_1_wacs(n, repeat, BOTH2(WACS_PI)); 3301 n = show_1_wacs(n, repeat, BOTH2(WACS_S1)); 3302 n = show_1_wacs(n, repeat, BOTH2(WACS_S3)); 3303 n = show_1_wacs(n, repeat, BOTH2(WACS_S7)); 3304 n = show_1_wacs(n, repeat, BOTH2(WACS_S9)); 3305#endif 3306} 3307 3308#undef MERGE_ATTR 3309 3310#define MERGE_ATTR(wch) merge_wide_attr(&temp, wch, attr, pair) 3311 3312static void 3313show_wbox_chars(int repeat, attr_t attr, short pair) 3314{ 3315 cchar_t temp; 3316 3317 (void) repeat; 3318 erase(); 3319 attron(A_BOLD); 3320 mvaddstr(0, 20, "Display of the Wide-ACS Line-Drawing Set"); 3321 attroff(A_BOLD); 3322 refresh(); 3323 3324 attr_set(attr, pair, 0); 3325 box_set(stdscr, 0, 0); 3326 attr_set(A_NORMAL, 0, 0); 3327 /* *INDENT-OFF* */ 3328 mvhline_set(LINES / 2, 0, MERGE_ATTR(WACS_HLINE), COLS); 3329 mvvline_set(0, COLS / 2, MERGE_ATTR(WACS_VLINE), LINES); 3330 mvadd_wch(0, COLS / 2, MERGE_ATTR(WACS_TTEE)); 3331 mvadd_wch(LINES / 2, COLS / 2, MERGE_ATTR(WACS_PLUS)); 3332 mvadd_wch(LINES - 1, COLS / 2, MERGE_ATTR(WACS_BTEE)); 3333 mvadd_wch(LINES / 2, 0, MERGE_ATTR(WACS_LTEE)); 3334 mvadd_wch(LINES / 2, COLS - 1, MERGE_ATTR(WACS_RTEE)); 3335 /* *INDENT-ON* */ 3336 3337} 3338 3339#undef MERGE_ATTR 3340 3341static int 3342show_2_wacs(int n, const char *name, const char *code, attr_t attr, short pair) 3343{ 3344 const int height = 16; 3345 int row = 2 + (n % height); 3346 int col = (n / height) * COLS / 2; 3347 char temp[80]; 3348 3349 mvprintw(row, col, "%*s : ", COLS / 4, name); 3350 attr_set(attr, pair, 0); 3351 addstr(strcpy(temp, code)); 3352 attr_set(A_NORMAL, 0, 0); 3353 return n + 1; 3354} 3355 3356#define SHOW_UTF8(n, name, code) show_2_wacs(n, name, code, attr, pair) 3357 3358static void 3359show_utf8_chars(int repeat, attr_t attr, short pair) 3360{ 3361 int n; 3362 3363 (void) repeat; 3364 erase(); 3365 attron(A_BOLD); 3366 mvaddstr(0, 20, "Display of the Wide-ACS Character Set"); 3367 attroff(A_BOLD); 3368 refresh(); 3369 /* *INDENT-OFF* */ 3370 n = SHOW_UTF8(0, "WACS_ULCORNER", "\342\224\214"); 3371 n = SHOW_UTF8(n, "WACS_URCORNER", "\342\224\220"); 3372 n = SHOW_UTF8(n, "WACS_LLCORNER", "\342\224\224"); 3373 n = SHOW_UTF8(n, "WACS_LRCORNER", "\342\224\230"); 3374 3375 n = SHOW_UTF8(n, "WACS_LTEE", "\342\224\234"); 3376 n = SHOW_UTF8(n, "WACS_RTEE", "\342\224\244"); 3377 n = SHOW_UTF8(n, "WACS_TTEE", "\342\224\254"); 3378 n = SHOW_UTF8(n, "WACS_BTEE", "\342\224\264"); 3379 3380 n = SHOW_UTF8(n, "WACS_HLINE", "\342\224\200"); 3381 n = SHOW_UTF8(n, "WACS_VLINE", "\342\224\202"); 3382 3383 n = SHOW_UTF8(n, "WACS_LARROW", "\342\206\220"); 3384 n = SHOW_UTF8(n, "WACS_RARROW", "\342\206\222"); 3385 n = SHOW_UTF8(n, "WACS_UARROW", "\342\206\221"); 3386 n = SHOW_UTF8(n, "WACS_DARROW", "\342\206\223"); 3387 3388 n = SHOW_UTF8(n, "WACS_BLOCK", "\342\226\256"); 3389 n = SHOW_UTF8(n, "WACS_BOARD", "\342\226\222"); 3390 n = SHOW_UTF8(n, "WACS_LANTERN", "\342\230\203"); 3391 n = SHOW_UTF8(n, "WACS_BULLET", "\302\267"); 3392 n = SHOW_UTF8(n, "WACS_CKBOARD", "\342\226\222"); 3393 n = SHOW_UTF8(n, "WACS_DEGREE", "\302\260"); 3394 n = SHOW_UTF8(n, "WACS_DIAMOND", "\342\227\206"); 3395 n = SHOW_UTF8(n, "WACS_PLMINUS", "\302\261"); 3396 n = SHOW_UTF8(n, "WACS_PLUS", "\342\224\274"); 3397 n = SHOW_UTF8(n, "WACS_GEQUAL", "\342\211\245"); 3398 n = SHOW_UTF8(n, "WACS_NEQUAL", "\342\211\240"); 3399 n = SHOW_UTF8(n, "WACS_LEQUAL", "\342\211\244"); 3400 3401 n = SHOW_UTF8(n, "WACS_STERLING", "\302\243"); 3402 n = SHOW_UTF8(n, "WACS_PI", "\317\200"); 3403 n = SHOW_UTF8(n, "WACS_S1", "\342\216\272"); 3404 n = SHOW_UTF8(n, "WACS_S3", "\342\216\273"); 3405 n = SHOW_UTF8(n, "WACS_S7", "\342\216\274"); 3406 n = SHOW_UTF8(n, "WACS_S9", "\342\216\275"); 3407 /* *INDENT-ON* */ 3408 3409} 3410 3411/* display the wide-ACS character set */ 3412static void 3413wide_acs_display(void) 3414{ 3415 int c = 'a'; 3416 int digit = 0; 3417 int repeat = 1; 3418 int space = ' '; 3419 chtype attr = A_NORMAL; 3420 int fg = COLOR_BLACK; 3421 int bg = COLOR_BLACK; 3422 unsigned at_code = 0; 3423 short pair = 0; 3424 void (*last_show_wacs) (int, attr_t, short) = 0; 3425 3426 do { 3427 switch (c) { 3428 case CTRL('L'): 3429 Repaint(); 3430 break; 3431 case 'a': 3432 ToggleAcs(last_show_wacs, show_wacs_chars); 3433 break; 3434 case 'x': 3435 ToggleAcs(last_show_wacs, show_wbox_chars); 3436 break; 3437 case 'u': 3438 ToggleAcs(last_show_wacs, show_utf8_chars); 3439 break; 3440 default: 3441 if (c < 256 && isdigit(c)) { 3442 digit = (c - '0'); 3443 last_show_wacs = 0; 3444 } else if (c == '+') { 3445 ++digit; 3446 last_show_wacs = 0; 3447 } else if (c == '-' && digit > 0) { 3448 --digit; 3449 last_show_wacs = 0; 3450 } else if (c == '>' && repeat < (COLS / 4)) { 3451 ++repeat; 3452 } else if (c == '<' && repeat > 1) { 3453 --repeat; 3454 } else if (c == '_') { 3455 space = (space == ' ') ? '_' : ' '; 3456 last_show_wacs = 0; 3457 } else if (cycle_attr(c, &at_code, &attr) 3458 || cycle_colors(c, &fg, &bg, &pair)) { 3459 if (last_show_wacs != 0) 3460 break; 3461 } else { 3462 beep(); 3463 break; 3464 } 3465 break; 3466 } 3467 if (last_show_wacs != 0) 3468 last_show_wacs(repeat, attr, pair); 3469 else 3470 show_upper_widechars(digit * 32 + 128, repeat, space, attr, pair); 3471 3472 mvprintw(LINES - 3, 0, 3473 "Select: a WACS, x box, u UTF-8, 0-9,+/- non-ASCII, </> repeat, ESC=quit"); 3474 if (use_colors) { 3475 mvprintw(LINES - 2, 0, 3476 "v/V, f/F, b/B cycle through video attributes (%s) and color %d/%d.", 3477 attrs_to_cycle[at_code].name, 3478 fg, bg); 3479 } else { 3480 mvprintw(LINES - 2, 0, 3481 "v/V cycles through video attributes (%s).", 3482 attrs_to_cycle[at_code].name); 3483 } 3484 refresh(); 3485 } while (!isQuit(c = Getchar())); 3486 3487 Pause(); 3488 erase(); 3489 endwin(); 3490} 3491 3492#endif 3493 3494/* 3495 * Graphic-rendition test (adapted from vttest) 3496 */ 3497static void 3498test_sgr_attributes(void) 3499{ 3500 int pass; 3501 3502 for (pass = 0; pass < 2; pass++) { 3503 chtype normal = ((pass == 0 ? A_NORMAL : A_REVERSE)) | BLANK; 3504 3505 /* Use non-default colors if possible to exercise bce a little */ 3506 if (use_colors) { 3507 init_pair(1, COLOR_WHITE, COLOR_BLUE); 3508 normal |= COLOR_PAIR(1); 3509 } 3510 bkgdset(normal); 3511 erase(); 3512 mvprintw(1, 20, "Graphic rendition test pattern:"); 3513 3514 mvprintw(4, 1, "vanilla"); 3515 3516#define set_sgr(mask) bkgdset((normal^(mask))); 3517 set_sgr(A_BOLD); 3518 mvprintw(4, 40, "bold"); 3519 3520 set_sgr(A_UNDERLINE); 3521 mvprintw(6, 6, "underline"); 3522 3523 set_sgr(A_BOLD | A_UNDERLINE); 3524 mvprintw(6, 45, "bold underline"); 3525 3526 set_sgr(A_BLINK); 3527 mvprintw(8, 1, "blink"); 3528 3529 set_sgr(A_BLINK | A_BOLD); 3530 mvprintw(8, 40, "bold blink"); 3531 3532 set_sgr(A_UNDERLINE | A_BLINK); 3533 mvprintw(10, 6, "underline blink"); 3534 3535 set_sgr(A_BOLD | A_UNDERLINE | A_BLINK); 3536 mvprintw(10, 45, "bold underline blink"); 3537 3538 set_sgr(A_REVERSE); 3539 mvprintw(12, 1, "negative"); 3540 3541 set_sgr(A_BOLD | A_REVERSE); 3542 mvprintw(12, 40, "bold negative"); 3543 3544 set_sgr(A_UNDERLINE | A_REVERSE); 3545 mvprintw(14, 6, "underline negative"); 3546 3547 set_sgr(A_BOLD | A_UNDERLINE | A_REVERSE); 3548 mvprintw(14, 45, "bold underline negative"); 3549 3550 set_sgr(A_BLINK | A_REVERSE); 3551 mvprintw(16, 1, "blink negative"); 3552 3553 set_sgr(A_BOLD | A_BLINK | A_REVERSE); 3554 mvprintw(16, 40, "bold blink negative"); 3555 3556 set_sgr(A_UNDERLINE | A_BLINK | A_REVERSE); 3557 mvprintw(18, 6, "underline blink negative"); 3558 3559 set_sgr(A_BOLD | A_UNDERLINE | A_BLINK | A_REVERSE); 3560 mvprintw(18, 45, "bold underline blink negative"); 3561 3562 bkgdset(normal); 3563 mvprintw(LINES - 2, 1, "%s background. ", pass == 0 ? "Dark" : 3564 "Light"); 3565 clrtoeol(); 3566 Pause(); 3567 } 3568 3569 bkgdset(A_NORMAL | BLANK); 3570 erase(); 3571 endwin(); 3572} 3573 3574/**************************************************************************** 3575 * 3576 * Windows and scrolling tester. 3577 * 3578 ****************************************************************************/ 3579 3580#define BOTLINES 4 /* number of line stolen from screen bottom */ 3581 3582typedef struct { 3583 int y, x; 3584} pair; 3585 3586#define FRAME struct frame 3587FRAME 3588{ 3589 FRAME *next, *last; 3590 bool do_scroll; 3591 bool do_keypad; 3592 WINDOW *wind; 3593}; 3594 3595#if defined(NCURSES_VERSION) 3596#if (NCURSES_VERSION_PATCH < 20070331) && NCURSES_EXT_FUNCS 3597#define is_keypad(win) (win)->_use_keypad 3598#define is_scrollok(win) (win)->_scroll 3599#elif !defined(is_keypad) 3600#define is_keypad(win) FALSE 3601#define is_scrollok(win) FALSE 3602#endif 3603#else 3604#define is_keypad(win) FALSE 3605#define is_scrollok(win) FALSE 3606#endif 3607 3608static WINDOW * 3609frame_win(FRAME * curp) 3610{ 3611 return (curp != 0) ? curp->wind : stdscr; 3612} 3613 3614/* We need to know if these flags are actually set, so don't look in FRAME. 3615 * These names are known to work with SVr4 curses as well as ncurses. The 3616 * _use_keypad name does not work with Solaris 8. 3617 */ 3618static bool 3619HaveKeypad(FRAME * curp) 3620{ 3621 WINDOW *win = frame_win(curp); 3622 (void) win; 3623 return is_keypad(win); 3624} 3625 3626static bool 3627HaveScroll(FRAME * curp) 3628{ 3629 WINDOW *win = frame_win(curp); 3630 (void) win; 3631 return is_scrollok(win); 3632} 3633 3634static void 3635newwin_legend(FRAME * curp) 3636{ 3637 static const struct { 3638 const char *msg; 3639 int code; 3640 } legend[] = { 3641 { 3642 "^C = create window", 0 3643 }, 3644 { 3645 "^N = next window", 0 3646 }, 3647 { 3648 "^P = previous window", 0 3649 }, 3650 { 3651 "^F = scroll forward", 0 3652 }, 3653 { 3654 "^B = scroll backward", 0 3655 }, 3656 { 3657 "^K = keypad(%s)", 1 3658 }, 3659 { 3660 "^S = scrollok(%s)", 2 3661 }, 3662 { 3663 "^W = save window to file", 0 3664 }, 3665 { 3666 "^R = restore window", 0 3667 }, 3668#if HAVE_WRESIZE 3669 { 3670 "^X = resize", 0 3671 }, 3672#endif 3673 { 3674 "^Q%s = exit", 3 3675 } 3676 }; 3677 size_t n; 3678 int x; 3679 bool do_keypad = HaveKeypad(curp); 3680 bool do_scroll = HaveScroll(curp); 3681 char buf[BUFSIZ]; 3682 3683 move(LINES - 4, 0); 3684 for (n = 0; n < SIZEOF(legend); n++) { 3685 switch (legend[n].code) { 3686 default: 3687 strcpy(buf, legend[n].msg); 3688 break; 3689 case 1: 3690 sprintf(buf, legend[n].msg, do_keypad ? "yes" : "no"); 3691 break; 3692 case 2: 3693 sprintf(buf, legend[n].msg, do_scroll ? "yes" : "no"); 3694 break; 3695 case 3: 3696 sprintf(buf, legend[n].msg, do_keypad ? "/ESC" : ""); 3697 break; 3698 } 3699 x = getcurx(stdscr); 3700 addstr((COLS < (x + 3 + (int) strlen(buf))) ? "\n" : (n ? ", " : "")); 3701 addstr(buf); 3702 } 3703 clrtoeol(); 3704} 3705 3706static void 3707transient(FRAME * curp, NCURSES_CONST char *msg) 3708{ 3709 newwin_legend(curp); 3710 if (msg) { 3711 mvaddstr(LINES - 1, 0, msg); 3712 refresh(); 3713 napms(1000); 3714 } 3715 3716 move(LINES - 1, 0); 3717 printw("%s characters are echoed, window should %sscroll.", 3718 HaveKeypad(curp) ? "Non-arrow" : "All other", 3719 HaveScroll(curp) ? "" : "not "); 3720 clrtoeol(); 3721} 3722 3723static void 3724newwin_report(FRAME * curp) 3725/* report on the cursor's current position, then restore it */ 3726{ 3727 WINDOW *win = frame_win(curp); 3728 int y, x; 3729 3730 if (win != stdscr) 3731 transient(curp, (char *) 0); 3732 getyx(win, y, x); 3733 move(LINES - 1, COLS - 17); 3734 printw("Y = %2d X = %2d", y, x); 3735 if (win != stdscr) 3736 refresh(); 3737 else 3738 wmove(win, y, x); 3739} 3740 3741static pair * 3742selectcell(int uli, int ulj, int lri, int lrj) 3743/* arrows keys move cursor, return location at current on non-arrow key */ 3744{ 3745 static pair res; /* result cell */ 3746 int si = lri - uli + 1; /* depth of the select area */ 3747 int sj = lrj - ulj + 1; /* width of the select area */ 3748 int i = 0, j = 0; /* offsets into the select area */ 3749 3750 res.y = uli; 3751 res.x = ulj; 3752 for (;;) { 3753 move(uli + i, ulj + j); 3754 newwin_report((FRAME *) 0); 3755 3756 switch (Getchar()) { 3757 case KEY_UP: 3758 i += si - 1; 3759 break; 3760 case KEY_DOWN: 3761 i++; 3762 break; 3763 case KEY_LEFT: 3764 j += sj - 1; 3765 break; 3766 case KEY_RIGHT: 3767 j++; 3768 break; 3769 case case_QUIT: 3770 return ((pair *) 0); 3771#ifdef NCURSES_MOUSE_VERSION 3772 case KEY_MOUSE: 3773 { 3774 MEVENT event; 3775 3776 getmouse(&event); 3777 if (event.y > uli && event.x > ulj) { 3778 i = event.y - uli; 3779 j = event.x - ulj; 3780 } else { 3781 beep(); 3782 break; 3783 } 3784 } 3785 /* FALLTHRU */ 3786#endif 3787 default: 3788 res.y = uli + i; 3789 res.x = ulj + j; 3790 return (&res); 3791 } 3792 i %= si; 3793 j %= sj; 3794 } 3795} 3796 3797static void 3798outerbox(pair ul, pair lr, bool onoff) 3799/* draw or erase a box *outside* the given pair of corners */ 3800{ 3801 mvaddch(ul.y - 1, lr.x - 1, onoff ? ACS_ULCORNER : ' '); 3802 mvaddch(ul.y - 1, lr.x + 1, onoff ? ACS_URCORNER : ' '); 3803 mvaddch(lr.y + 1, lr.x + 1, onoff ? ACS_LRCORNER : ' '); 3804 mvaddch(lr.y + 1, ul.x - 1, onoff ? ACS_LLCORNER : ' '); 3805 move(ul.y - 1, ul.x); 3806 hline(onoff ? ACS_HLINE : ' ', lr.x - ul.x + 1); 3807 move(ul.y, ul.x - 1); 3808 vline(onoff ? ACS_VLINE : ' ', lr.y - ul.y + 1); 3809 move(lr.y + 1, ul.x); 3810 hline(onoff ? ACS_HLINE : ' ', lr.x - ul.x + 1); 3811 move(ul.y, lr.x + 1); 3812 vline(onoff ? ACS_VLINE : ' ', lr.y - ul.y + 1); 3813} 3814 3815static WINDOW * 3816getwindow(void) 3817/* Ask user for a window definition */ 3818{ 3819 WINDOW *rwindow; 3820 pair ul, lr, *tmp; 3821 3822 move(0, 0); 3823 clrtoeol(); 3824 addstr("Use arrows to move cursor, anything else to mark corner 1"); 3825 refresh(); 3826 if ((tmp = selectcell(2, 1, LINES - BOTLINES - 2, COLS - 2)) == (pair *) 0) 3827 return ((WINDOW *) 0); 3828 memcpy(&ul, tmp, sizeof(pair)); 3829 mvaddch(ul.y - 1, ul.x - 1, ACS_ULCORNER); 3830 move(0, 0); 3831 clrtoeol(); 3832 addstr("Use arrows to move cursor, anything else to mark corner 2"); 3833 refresh(); 3834 if ((tmp = selectcell(ul.y, ul.x, LINES - BOTLINES - 2, COLS - 2)) == 3835 (pair *) 0) 3836 return ((WINDOW *) 0); 3837 memcpy(&lr, tmp, sizeof(pair)); 3838 3839 rwindow = subwin(stdscr, lr.y - ul.y + 1, lr.x - ul.x + 1, ul.y, ul.x); 3840 3841 outerbox(ul, lr, TRUE); 3842 refresh(); 3843 3844 wrefresh(rwindow); 3845 3846 move(0, 0); 3847 clrtoeol(); 3848 return (rwindow); 3849} 3850 3851static void 3852newwin_move(FRAME * curp, int dy, int dx) 3853{ 3854 WINDOW *win = frame_win(curp); 3855 int cur_y, cur_x; 3856 int max_y, max_x; 3857 3858 getyx(win, cur_y, cur_x); 3859 getmaxyx(win, max_y, max_x); 3860 if ((cur_x += dx) < 0) 3861 cur_x = 0; 3862 else if (cur_x >= max_x) 3863 cur_x = max_x - 1; 3864 if ((cur_y += dy) < 0) 3865 cur_y = 0; 3866 else if (cur_y >= max_y) 3867 cur_y = max_y - 1; 3868 wmove(win, cur_y, cur_x); 3869} 3870 3871static FRAME * 3872delete_framed(FRAME * fp, bool showit) 3873{ 3874 FRAME *np = 0; 3875 3876 if (fp != 0) { 3877 fp->last->next = fp->next; 3878 fp->next->last = fp->last; 3879 3880 if (showit) { 3881 werase(fp->wind); 3882 wrefresh(fp->wind); 3883 } 3884 delwin(fp->wind); 3885 3886 np = (fp == fp->next) ? 0 : fp->next; 3887 free(fp); 3888 } 3889 return np; 3890} 3891 3892static void 3893acs_and_scroll(void) 3894/* Demonstrate windows */ 3895{ 3896 int c; 3897 FRAME *current = (FRAME *) 0, *neww; 3898 WINDOW *usescr = stdscr; 3899#if HAVE_PUTWIN && HAVE_GETWIN 3900 FILE *fp; 3901#endif 3902 3903#define DUMPFILE "screendump" 3904 3905#ifdef NCURSES_MOUSE_VERSION 3906 mousemask(BUTTON1_CLICKED, (mmask_t *) 0); 3907#endif 3908 c = CTRL('C'); 3909 raw(); 3910 do { 3911 transient((FRAME *) 0, (char *) 0); 3912 switch (c) { 3913 case CTRL('C'): 3914 if ((neww = typeCalloc(FRAME, 1)) == 0) { 3915 goto breakout; 3916 } 3917 if ((neww->wind = getwindow()) == (WINDOW *) 0) { 3918 free(neww); 3919 goto breakout; 3920 } 3921 3922 if (current == 0) { /* First element, */ 3923 neww->next = neww; /* so point it at itself */ 3924 neww->last = neww; 3925 } else { 3926 neww->next = current->next; 3927 neww->last = current; 3928 neww->last->next = neww; 3929 neww->next->last = neww; 3930 } 3931 current = neww; 3932 /* SVr4 curses sets the keypad on all newly-created windows to 3933 * false. Someone reported that PDCurses makes new windows inherit 3934 * this flag. Remove the following 'keypad()' call to test this 3935 */ 3936 keypad(current->wind, TRUE); 3937 current->do_keypad = HaveKeypad(current); 3938 current->do_scroll = HaveScroll(current); 3939 break; 3940 3941 case CTRL('N'): /* go to next window */ 3942 if (current) 3943 current = current->next; 3944 break; 3945 3946 case CTRL('P'): /* go to previous window */ 3947 if (current) 3948 current = current->last; 3949 break; 3950 3951 case CTRL('F'): /* scroll current window forward */ 3952 if (current) 3953 wscrl(frame_win(current), 1); 3954 break; 3955 3956 case CTRL('B'): /* scroll current window backwards */ 3957 if (current) 3958 wscrl(frame_win(current), -1); 3959 break; 3960 3961 case CTRL('K'): /* toggle keypad mode for current */ 3962 if (current) { 3963 current->do_keypad = !current->do_keypad; 3964 keypad(current->wind, current->do_keypad); 3965 } 3966 break; 3967 3968 case CTRL('S'): 3969 if (current) { 3970 current->do_scroll = !current->do_scroll; 3971 scrollok(current->wind, current->do_scroll); 3972 } 3973 break; 3974 3975#if HAVE_PUTWIN && HAVE_GETWIN 3976 case CTRL('W'): /* save and delete window */ 3977 if ((current != 0) && (current == current->next)) { 3978 transient(current, "Will not save/delete ONLY window"); 3979 break; 3980 } else if ((fp = fopen(DUMPFILE, "w")) == (FILE *) 0) { 3981 transient(current, "Can't open screen dump file"); 3982 } else { 3983 (void) putwin(frame_win(current), fp); 3984 (void) fclose(fp); 3985 3986 current = delete_framed(current, TRUE); 3987 } 3988 break; 3989 3990 case CTRL('R'): /* restore window */ 3991 if ((fp = fopen(DUMPFILE, "r")) == (FILE *) 0) { 3992 transient(current, "Can't open screen dump file"); 3993 } else { 3994 if ((neww = typeCalloc(FRAME, 1)) != 0) { 3995 3996 neww->next = current ? current->next : 0; 3997 neww->last = current; 3998 neww->last->next = neww; 3999 neww->next->last = neww; 4000 4001 neww->wind = getwin(fp); 4002 4003 wrefresh(neww->wind); 4004 } 4005 (void) fclose(fp); 4006 } 4007 break; 4008#endif 4009 4010#if HAVE_WRESIZE 4011 case CTRL('X'): /* resize window */ 4012 if (current) { 4013 pair *tmp, ul, lr; 4014 int i, mx, my; 4015 4016 move(0, 0); 4017 clrtoeol(); 4018 addstr("Use arrows to move cursor, anything else to mark new corner"); 4019 refresh(); 4020 4021 getbegyx(current->wind, ul.y, ul.x); 4022 4023 tmp = selectcell(ul.y, ul.x, LINES - BOTLINES - 2, COLS - 2); 4024 if (tmp == (pair *) 0) { 4025 beep(); 4026 break; 4027 } 4028 4029 getmaxyx(current->wind, lr.y, lr.x); 4030 lr.y += (ul.y - 1); 4031 lr.x += (ul.x - 1); 4032 outerbox(ul, lr, FALSE); 4033 wnoutrefresh(stdscr); 4034 4035 /* strictly cosmetic hack for the test */ 4036 getmaxyx(current->wind, my, mx); 4037 if (my > tmp->y - ul.y) { 4038 getyx(current->wind, lr.y, lr.x); 4039 wmove(current->wind, tmp->y - ul.y + 1, 0); 4040 wclrtobot(current->wind); 4041 wmove(current->wind, lr.y, lr.x); 4042 } 4043 if (mx > tmp->x - ul.x) 4044 for (i = 0; i < my; i++) { 4045 wmove(current->wind, i, tmp->x - ul.x + 1); 4046 wclrtoeol(current->wind); 4047 } 4048 wnoutrefresh(current->wind); 4049 4050 memcpy(&lr, tmp, sizeof(pair)); 4051 (void) wresize(current->wind, lr.y - ul.y + 0, lr.x - ul.x + 0); 4052 4053 getbegyx(current->wind, ul.y, ul.x); 4054 getmaxyx(current->wind, lr.y, lr.x); 4055 lr.y += (ul.y - 1); 4056 lr.x += (ul.x - 1); 4057 outerbox(ul, lr, TRUE); 4058 wnoutrefresh(stdscr); 4059 4060 wnoutrefresh(current->wind); 4061 move(0, 0); 4062 clrtoeol(); 4063 doupdate(); 4064 } 4065 break; 4066#endif /* HAVE_WRESIZE */ 4067 4068 case KEY_F(10): /* undocumented --- use this to test area clears */ 4069 selectcell(0, 0, LINES - 1, COLS - 1); 4070 clrtobot(); 4071 refresh(); 4072 break; 4073 4074 case KEY_UP: 4075 newwin_move(current, -1, 0); 4076 break; 4077 case KEY_DOWN: 4078 newwin_move(current, 1, 0); 4079 break; 4080 case KEY_LEFT: 4081 newwin_move(current, 0, -1); 4082 break; 4083 case KEY_RIGHT: 4084 newwin_move(current, 0, 1); 4085 break; 4086 4087 case KEY_BACKSPACE: 4088 /* FALLTHROUGH */ 4089 case KEY_DC: 4090 { 4091 int y, x; 4092 getyx(frame_win(current), y, x); 4093 if (--x < 0) { 4094 if (--y < 0) 4095 break; 4096 x = getmaxx(frame_win(current)) - 1; 4097 } 4098 mvwdelch(frame_win(current), y, x); 4099 } 4100 break; 4101 4102 case '\r': 4103 c = '\n'; 4104 /* FALLTHROUGH */ 4105 4106 default: 4107 if (current) 4108 waddch(current->wind, (chtype) c); 4109 else 4110 beep(); 4111 break; 4112 } 4113 newwin_report(current); 4114 usescr = frame_win(current); 4115 wrefresh(usescr); 4116 } while 4117 (!isQuit(c = wGetchar(usescr)) 4118 && (c != ERR)); 4119 4120 breakout: 4121 while (current != 0) 4122 current = delete_framed(current, FALSE); 4123 4124 scrollok(stdscr, TRUE); /* reset to driver's default */ 4125#ifdef NCURSES_MOUSE_VERSION 4126 mousemask(0, (mmask_t *) 0); 4127#endif 4128 noraw(); 4129 erase(); 4130 endwin(); 4131} 4132 4133/**************************************************************************** 4134 * 4135 * Panels tester 4136 * 4137 ****************************************************************************/ 4138 4139#if USE_LIBPANEL 4140static int nap_msec = 1; 4141 4142static NCURSES_CONST char *mod[] = 4143{ 4144 "test ", 4145 "TEST ", 4146 "(**) ", 4147 "*()* ", 4148 "<--> ", 4149 "LAST " 4150}; 4151 4152/*+------------------------------------------------------------------------- 4153 wait_a_while(msec) 4154--------------------------------------------------------------------------*/ 4155static void 4156wait_a_while(int msec GCC_UNUSED) 4157{ 4158#if HAVE_NAPMS 4159 if (nap_msec == 1) 4160 wGetchar(stdscr); 4161 else 4162 napms(nap_msec); 4163#else 4164 if (nap_msec == 1) 4165 wGetchar(stdscr); 4166 else if (msec > 1000) 4167 sleep((unsigned) msec / 1000); 4168 else 4169 sleep(1); 4170#endif 4171} /* end of wait_a_while */ 4172 4173/*+------------------------------------------------------------------------- 4174 saywhat(text) 4175--------------------------------------------------------------------------*/ 4176static void 4177saywhat(NCURSES_CONST char *text) 4178{ 4179 wmove(stdscr, LINES - 1, 0); 4180 wclrtoeol(stdscr); 4181 if (text != 0 && *text != '\0') { 4182 waddstr(stdscr, text); 4183 waddstr(stdscr, "; "); 4184 } 4185 waddstr(stdscr, "press any key to continue"); 4186} /* end of saywhat */ 4187 4188/*+------------------------------------------------------------------------- 4189 mkpanel(rows,cols,tly,tlx) - alloc a win and panel and associate them 4190--------------------------------------------------------------------------*/ 4191static PANEL * 4192mkpanel(short color, int rows, int cols, int tly, int tlx) 4193{ 4194 WINDOW *win; 4195 PANEL *pan = 0; 4196 4197 if ((win = newwin(rows, cols, tly, tlx)) != 0) { 4198 if ((pan = new_panel(win)) == 0) { 4199 delwin(win); 4200 } else if (use_colors) { 4201 short fg = (short) ((color == COLOR_BLUE) ? COLOR_WHITE : COLOR_BLACK); 4202 short bg = color; 4203 4204 init_pair(color, fg, bg); 4205 wbkgdset(win, (chtype) (COLOR_PAIR(color) | ' ')); 4206 } else { 4207 wbkgdset(win, A_BOLD | ' '); 4208 } 4209 } 4210 return pan; 4211} /* end of mkpanel */ 4212 4213/*+------------------------------------------------------------------------- 4214 rmpanel(pan) 4215--------------------------------------------------------------------------*/ 4216static void 4217rmpanel(PANEL * pan) 4218{ 4219 WINDOW *win = panel_window(pan); 4220 del_panel(pan); 4221 delwin(win); 4222} /* end of rmpanel */ 4223 4224/*+------------------------------------------------------------------------- 4225 pflush() 4226--------------------------------------------------------------------------*/ 4227static void 4228pflush(void) 4229{ 4230 update_panels(); 4231 doupdate(); 4232} /* end of pflush */ 4233 4234/*+------------------------------------------------------------------------- 4235 fill_panel(win) 4236--------------------------------------------------------------------------*/ 4237static void 4238init_panel(void) 4239{ 4240 register int y, x; 4241 4242 for (y = 0; y < LINES - 1; y++) { 4243 for (x = 0; x < COLS; x++) 4244 wprintw(stdscr, "%d", (y + x) % 10); 4245 } 4246} 4247 4248static void 4249fill_panel(PANEL * pan) 4250{ 4251 WINDOW *win = panel_window(pan); 4252 const char *userptr = (const char *) panel_userptr(pan); 4253 int num = (userptr && *userptr) ? userptr[1] : '?'; 4254 int y, x; 4255 4256 wmove(win, 1, 1); 4257 wprintw(win, "-pan%c-", num); 4258 wclrtoeol(win); 4259 box(win, 0, 0); 4260 for (y = 2; y < getmaxy(win) - 1; y++) { 4261 for (x = 1; x < getmaxx(win) - 1; x++) { 4262 wmove(win, y, x); 4263 waddch(win, UChar(num)); 4264 } 4265 } 4266} 4267 4268#if USE_WIDEC_SUPPORT 4269static void 4270init_wide_panel(void) 4271{ 4272 int digit; 4273 cchar_t temp[10]; 4274 4275 for (digit = 0; digit < 10; ++digit) 4276 make_fullwidth_digit(&temp[digit], digit); 4277 4278 do { 4279 int y, x; 4280 getyx(stdscr, y, x); 4281 digit = (y + x / 2) % 10; 4282 } while (add_wch(&temp[digit]) != ERR); 4283} 4284 4285static void 4286fill_wide_panel(PANEL * pan) 4287{ 4288 WINDOW *win = panel_window(pan); 4289 const char *userptr = (const char *) panel_userptr(pan); 4290 int num = (userptr && *userptr) ? userptr[1] : '?'; 4291 int y, x; 4292 4293 wmove(win, 1, 1); 4294 wprintw(win, "-pan%c-", num); 4295 wclrtoeol(win); 4296 box(win, 0, 0); 4297 for (y = 2; y < getmaxy(win) - 1; y++) { 4298 for (x = 1; x < getmaxx(win) - 1; x++) { 4299 wmove(win, y, x); 4300 waddch(win, UChar(num)); 4301 } 4302 } 4303} 4304#endif 4305 4306#define MAX_PANELS 5 4307 4308static void 4309canned_panel(PANEL * px[MAX_PANELS + 1], NCURSES_CONST char *cmd) 4310{ 4311 int which = cmd[1] - '0'; 4312 4313 saywhat(cmd); 4314 switch (*cmd) { 4315 case 'h': 4316 hide_panel(px[which]); 4317 break; 4318 case 's': 4319 show_panel(px[which]); 4320 break; 4321 case 't': 4322 top_panel(px[which]); 4323 break; 4324 case 'b': 4325 bottom_panel(px[which]); 4326 break; 4327 case 'd': 4328 rmpanel(px[which]); 4329 break; 4330 } 4331 pflush(); 4332 wait_a_while(nap_msec); 4333} 4334 4335static void 4336demo_panels(void (*InitPanel) (void), void (*FillPanel) (PANEL *)) 4337{ 4338 int count; 4339 int itmp; 4340 PANEL *px[MAX_PANELS + 1]; 4341 4342 scrollok(stdscr, FALSE); /* we don't want stdscr to scroll! */ 4343 refresh(); 4344 4345 InitPanel(); 4346 for (count = 0; count < 5; count++) { 4347 px[1] = mkpanel(COLOR_RED, 4348 LINES / 2 - 2, 4349 COLS / 8 + 1, 4350 0, 4351 0); 4352 set_panel_userptr(px[1], (NCURSES_CONST void *) "p1"); 4353 4354 px[2] = mkpanel(COLOR_GREEN, 4355 LINES / 2 + 1, 4356 COLS / 7, 4357 LINES / 4, 4358 COLS / 10); 4359 set_panel_userptr(px[2], (NCURSES_CONST void *) "p2"); 4360 4361 px[3] = mkpanel(COLOR_YELLOW, 4362 LINES / 4, 4363 COLS / 10, 4364 LINES / 2, 4365 COLS / 9); 4366 set_panel_userptr(px[3], (NCURSES_CONST void *) "p3"); 4367 4368 px[4] = mkpanel(COLOR_BLUE, 4369 LINES / 2 - 2, 4370 COLS / 8, 4371 LINES / 2 - 2, 4372 COLS / 3); 4373 set_panel_userptr(px[4], (NCURSES_CONST void *) "p4"); 4374 4375 px[5] = mkpanel(COLOR_MAGENTA, 4376 LINES / 2 - 2, 4377 COLS / 8, 4378 LINES / 2, 4379 COLS / 2 - 2); 4380 set_panel_userptr(px[5], (NCURSES_CONST void *) "p5"); 4381 4382 FillPanel(px[1]); 4383 FillPanel(px[2]); 4384 FillPanel(px[3]); 4385 FillPanel(px[4]); 4386 FillPanel(px[5]); 4387 4388 hide_panel(px[4]); 4389 hide_panel(px[5]); 4390 pflush(); 4391 saywhat(""); 4392 wait_a_while(nap_msec); 4393 4394 saywhat("h3 s1 s2 s4 s5"); 4395 move_panel(px[1], 0, 0); 4396 hide_panel(px[3]); 4397 show_panel(px[1]); 4398 show_panel(px[2]); 4399 show_panel(px[4]); 4400 show_panel(px[5]); 4401 pflush(); 4402 wait_a_while(nap_msec); 4403 4404 canned_panel(px, "s1"); 4405 canned_panel(px, "s2"); 4406 4407 saywhat("m2"); 4408 move_panel(px[2], LINES / 3 + 1, COLS / 8); 4409 pflush(); 4410 wait_a_while(nap_msec); 4411 4412 canned_panel(px, "s3"); 4413 4414 saywhat("m3"); 4415 move_panel(px[3], LINES / 4 + 1, COLS / 15); 4416 pflush(); 4417 wait_a_while(nap_msec); 4418 4419 canned_panel(px, "b3"); 4420 canned_panel(px, "s4"); 4421 canned_panel(px, "s5"); 4422 canned_panel(px, "t3"); 4423 canned_panel(px, "t1"); 4424 canned_panel(px, "t2"); 4425 canned_panel(px, "t3"); 4426 canned_panel(px, "t4"); 4427 4428 for (itmp = 0; itmp < 6; itmp++) { 4429 WINDOW *w4 = panel_window(px[4]); 4430 WINDOW *w5 = panel_window(px[5]); 4431 4432 saywhat("m4"); 4433 wmove(w4, LINES / 8, 1); 4434 waddstr(w4, mod[itmp]); 4435 move_panel(px[4], LINES / 6, itmp * (COLS / 8)); 4436 wmove(w5, LINES / 6, 1); 4437 waddstr(w5, mod[itmp]); 4438 pflush(); 4439 wait_a_while(nap_msec); 4440 4441 saywhat("m5"); 4442 wmove(w4, LINES / 6, 1); 4443 waddstr(w4, mod[itmp]); 4444 move_panel(px[5], LINES / 3 - 1, (itmp * 10) + 6); 4445 wmove(w5, LINES / 8, 1); 4446 waddstr(w5, mod[itmp]); 4447 pflush(); 4448 wait_a_while(nap_msec); 4449 } 4450 4451 saywhat("m4"); 4452 move_panel(px[4], LINES / 6, itmp * (COLS / 8)); 4453 pflush(); 4454 wait_a_while(nap_msec); 4455 4456 canned_panel(px, "t5"); 4457 canned_panel(px, "t2"); 4458 canned_panel(px, "t1"); 4459 canned_panel(px, "d2"); 4460 canned_panel(px, "h3"); 4461 canned_panel(px, "d1"); 4462 canned_panel(px, "d4"); 4463 canned_panel(px, "d5"); 4464 canned_panel(px, "d3"); 4465 4466 wait_a_while(nap_msec); 4467 if (nap_msec == 1) 4468 break; 4469 nap_msec = 100L; 4470 } 4471 4472 erase(); 4473 endwin(); 4474} 4475#endif /* USE_LIBPANEL */ 4476 4477/**************************************************************************** 4478 * 4479 * Pad tester 4480 * 4481 ****************************************************************************/ 4482 4483#define GRIDSIZE 3 4484 4485static bool pending_pan = FALSE; 4486static bool show_panner_legend = TRUE; 4487 4488static int 4489panner_legend(int line) 4490{ 4491 static const char *const legend[] = 4492 { 4493 "Use arrow keys (or U,D,L,R) to pan, ESC to quit, ! to shell-out.", 4494 "Use +,- (or j,k) to grow/shrink the panner vertically.", 4495 "Use <,> (or h,l) to grow/shrink the panner horizontally.", 4496 "Number repeats. Toggle legend:? filler:a timer:t scrollmark:s." 4497 }; 4498 int n = ((int) SIZEOF(legend) - (LINES - line)); 4499 if (line < LINES && (n >= 0)) { 4500 move(line, 0); 4501 if (show_panner_legend) 4502 printw("%s", legend[n]); 4503 clrtoeol(); 4504 return show_panner_legend; 4505 } 4506 return FALSE; 4507} 4508 4509static void 4510panner_h_cleanup(int from_y, int from_x, int to_x) 4511{ 4512 if (!panner_legend(from_y)) 4513 do_h_line(from_y, from_x, ' ', to_x); 4514} 4515 4516static void 4517panner_v_cleanup(int from_y, int from_x, int to_y) 4518{ 4519 if (!panner_legend(from_y)) 4520 do_v_line(from_y, from_x, ' ', to_y); 4521} 4522 4523static void 4524fill_pad(WINDOW *panpad, bool pan_lines) 4525{ 4526 int y, x; 4527 unsigned gridcount = 0; 4528 4529 wmove(panpad, 0, 0); 4530 for (y = 0; y < getmaxy(panpad); y++) { 4531 for (x = 0; x < getmaxx(panpad); x++) { 4532 if (y % GRIDSIZE == 0 && x % GRIDSIZE == 0) { 4533 if (y == 0 && x == 0) 4534 waddch(panpad, pan_lines ? ACS_ULCORNER : '+'); 4535 else if (y == 0) 4536 waddch(panpad, pan_lines ? ACS_TTEE : '+'); 4537 else if (y == 0 || x == 0) 4538 waddch(panpad, pan_lines ? ACS_LTEE : '+'); 4539 else 4540 waddch(panpad, (chtype) ((pan_lines ? 'a' : 'A') + 4541 (int) (gridcount++ % 26))); 4542 } else if (y % GRIDSIZE == 0) 4543 waddch(panpad, pan_lines ? ACS_HLINE : '-'); 4544 else if (x % GRIDSIZE == 0) 4545 waddch(panpad, pan_lines ? ACS_VLINE : '|'); 4546 else 4547 waddch(panpad, ' '); 4548 } 4549 } 4550} 4551 4552static void 4553panner(WINDOW *pad, 4554 int top_x, int top_y, int porty, int portx, 4555 int (*pgetc) (WINDOW *)) 4556{ 4557#if HAVE_GETTIMEOFDAY 4558 struct timeval before, after; 4559 bool timing = TRUE; 4560#endif 4561 bool pan_lines = FALSE; 4562 bool scrollers = TRUE; 4563 int basex = 0; 4564 int basey = 0; 4565 int pxmax, pymax, lowend, highend, c; 4566 4567 getmaxyx(pad, pymax, pxmax); 4568 scrollok(stdscr, FALSE); /* we don't want stdscr to scroll! */ 4569 4570 c = KEY_REFRESH; 4571 do { 4572#ifdef NCURSES_VERSION 4573 /* 4574 * During shell-out, the user may have resized the window. Adjust 4575 * the port size of the pad to accommodate this. Ncurses automatically 4576 * resizes all of the normal windows to fit on the new screen. 4577 */ 4578 if (top_x > COLS) 4579 top_x = COLS; 4580 if (portx > COLS) 4581 portx = COLS; 4582 if (top_y > LINES) 4583 top_y = LINES; 4584 if (porty > LINES) 4585 porty = LINES; 4586#endif 4587 switch (c) { 4588 case KEY_REFRESH: 4589 erase(); 4590 4591 /* FALLTHRU */ 4592 case '?': 4593 if (c == '?') 4594 show_panner_legend = !show_panner_legend; 4595 panner_legend(LINES - 4); 4596 panner_legend(LINES - 3); 4597 panner_legend(LINES - 2); 4598 panner_legend(LINES - 1); 4599 break; 4600 case 'a': 4601 pan_lines = !pan_lines; 4602 fill_pad(pad, pan_lines); 4603 pending_pan = FALSE; 4604 break; 4605 4606#if HAVE_GETTIMEOFDAY 4607 case 't': 4608 timing = !timing; 4609 if (!timing) 4610 panner_legend(LINES - 1); 4611 break; 4612#endif 4613 case 's': 4614 scrollers = !scrollers; 4615 break; 4616 4617 /* Move the top-left corner of the pad, keeping the bottom-right 4618 * corner fixed. 4619 */ 4620 case 'h': /* increase-columns: move left edge to left */ 4621 if (top_x <= 0) 4622 beep(); 4623 else { 4624 panner_v_cleanup(top_y, top_x, porty); 4625 top_x--; 4626 } 4627 break; 4628 4629 case 'j': /* decrease-lines: move top-edge down */ 4630 if (top_y >= porty) 4631 beep(); 4632 else { 4633 panner_h_cleanup(top_y - 1, top_x - (top_x > 0), portx); 4634 top_y++; 4635 } 4636 break; 4637 4638 case 'k': /* increase-lines: move top-edge up */ 4639 if (top_y <= 0) 4640 beep(); 4641 else { 4642 top_y--; 4643 panner_h_cleanup(top_y, top_x, portx); 4644 } 4645 break; 4646 4647 case 'l': /* decrease-columns: move left-edge to right */ 4648 if (top_x >= portx) 4649 beep(); 4650 else { 4651 panner_v_cleanup(top_y - (top_y > 0), top_x - 1, porty); 4652 top_x++; 4653 } 4654 break; 4655 4656 /* Move the bottom-right corner of the pad, keeping the top-left 4657 * corner fixed. 4658 */ 4659 case KEY_IC: /* increase-columns: move right-edge to right */ 4660 if (portx >= pxmax || portx >= COLS) 4661 beep(); 4662 else { 4663 panner_v_cleanup(top_y - (top_y > 0), portx - 1, porty); 4664 ++portx; 4665 } 4666 break; 4667 4668 case KEY_IL: /* increase-lines: move bottom-edge down */ 4669 if (porty >= pymax || porty >= LINES) 4670 beep(); 4671 else { 4672 panner_h_cleanup(porty - 1, top_x - (top_x > 0), portx); 4673 ++porty; 4674 } 4675 break; 4676 4677 case KEY_DC: /* decrease-columns: move bottom edge up */ 4678 if (portx <= top_x) 4679 beep(); 4680 else { 4681 portx--; 4682 panner_v_cleanup(top_y - (top_y > 0), portx, porty); 4683 } 4684 break; 4685 4686 case KEY_DL: /* decrease-lines */ 4687 if (porty <= top_y) 4688 beep(); 4689 else { 4690 porty--; 4691 panner_h_cleanup(porty, top_x - (top_x > 0), portx); 4692 } 4693 break; 4694 4695 case KEY_LEFT: /* pan leftwards */ 4696 if (basex > 0) 4697 basex--; 4698 else 4699 beep(); 4700 break; 4701 4702 case KEY_RIGHT: /* pan rightwards */ 4703 if (basex + portx - (pymax > porty) < pxmax) 4704 basex++; 4705 else 4706 beep(); 4707 break; 4708 4709 case KEY_UP: /* pan upwards */ 4710 if (basey > 0) 4711 basey--; 4712 else 4713 beep(); 4714 break; 4715 4716 case KEY_DOWN: /* pan downwards */ 4717 if (basey + porty - (pxmax > portx) < pymax) 4718 basey++; 4719 else 4720 beep(); 4721 break; 4722 4723 case 'H': 4724 case KEY_HOME: 4725 case KEY_FIND: 4726 basey = 0; 4727 break; 4728 4729 case 'E': 4730 case KEY_END: 4731 case KEY_SELECT: 4732 basey = pymax - porty; 4733 if (basey < 0) 4734 basey = 0; 4735 break; 4736 4737 default: 4738 beep(); 4739 break; 4740 } 4741 4742 mvaddch(top_y - 1, top_x - 1, ACS_ULCORNER); 4743 do_v_line(top_y, top_x - 1, ACS_VLINE, porty); 4744 do_h_line(top_y - 1, top_x, ACS_HLINE, portx); 4745 4746 if (scrollers && (pxmax > portx - 1)) { 4747 int length = (portx - top_x - 1); 4748 float ratio = ((float) length) / ((float) pxmax); 4749 4750 lowend = (int) ((float) top_x + ((float) basex * ratio)); 4751 highend = (int) ((float) top_x + ((float) (basex + length) * ratio)); 4752 4753 do_h_line(porty - 1, top_x, ACS_HLINE, lowend); 4754 if (highend < portx) { 4755 attron(A_REVERSE); 4756 do_h_line(porty - 1, lowend, ' ', highend + 1); 4757 attroff(A_REVERSE); 4758 do_h_line(porty - 1, highend + 1, ACS_HLINE, portx); 4759 } 4760 } else 4761 do_h_line(porty - 1, top_x, ACS_HLINE, portx); 4762 4763 if (scrollers && (pymax > porty - 1)) { 4764 int length = (porty - top_y - 1); 4765 float ratio = ((float) length) / ((float) pymax); 4766 4767 lowend = (int) ((float) top_y + ((float) basey * ratio)); 4768 highend = (int) ((float) top_y + ((float) (basey + length) * ratio)); 4769 4770 do_v_line(top_y, portx - 1, ACS_VLINE, lowend); 4771 if (highend < porty) { 4772 attron(A_REVERSE); 4773 do_v_line(lowend, portx - 1, ' ', highend + 1); 4774 attroff(A_REVERSE); 4775 do_v_line(highend + 1, portx - 1, ACS_VLINE, porty); 4776 } 4777 } else 4778 do_v_line(top_y, portx - 1, ACS_VLINE, porty); 4779 4780 mvaddch(top_y - 1, portx - 1, ACS_URCORNER); 4781 mvaddch(porty - 1, top_x - 1, ACS_LLCORNER); 4782 mvaddch(porty - 1, portx - 1, ACS_LRCORNER); 4783 4784 if (!pending_pan) { 4785#if HAVE_GETTIMEOFDAY 4786 gettimeofday(&before, 0); 4787#endif 4788 wnoutrefresh(stdscr); 4789 4790 pnoutrefresh(pad, 4791 basey, basex, 4792 top_y, top_x, 4793 porty - (pxmax > portx) - 1, 4794 portx - (pymax > porty) - 1); 4795 4796 doupdate(); 4797#if HAVE_GETTIMEOFDAY 4798 if (timing) { 4799 double elapsed; 4800 gettimeofday(&after, 0); 4801 elapsed = (after.tv_sec + after.tv_usec / 1.0e6) 4802 - (before.tv_sec + before.tv_usec / 1.0e6); 4803 move(LINES - 1, COLS - 12); 4804 printw("Secs: %2.03f", elapsed); 4805 refresh(); 4806 } 4807#endif 4808 } 4809 4810 } while 4811 ((c = pgetc(pad)) != KEY_EXIT); 4812 4813 scrollok(stdscr, TRUE); /* reset to driver's default */ 4814} 4815 4816static int 4817padgetch(WINDOW *win) 4818{ 4819 static int count; 4820 static int last; 4821 int c; 4822 4823 if ((pending_pan = (count > 0)) != FALSE) { 4824 count--; 4825 pending_pan = (count != 0); 4826 } else { 4827 for (;;) { 4828 switch (c = wGetchar(win)) { 4829 case '!': 4830 ShellOut(FALSE); 4831 /* FALLTHRU */ 4832 case CTRL('r'): 4833 endwin(); 4834 refresh(); 4835 c = KEY_REFRESH; 4836 break; 4837 case CTRL('l'): 4838 c = KEY_REFRESH; 4839 break; 4840 case 'U': 4841 c = KEY_UP; 4842 break; 4843 case 'D': 4844 c = KEY_DOWN; 4845 break; 4846 case 'R': 4847 c = KEY_RIGHT; 4848 break; 4849 case 'L': 4850 c = KEY_LEFT; 4851 break; 4852 case '+': 4853 c = KEY_IL; 4854 break; 4855 case '-': 4856 c = KEY_DL; 4857 break; 4858 case '>': 4859 c = KEY_IC; 4860 break; 4861 case '<': 4862 c = KEY_DC; 4863 break; 4864 case ERR: /* FALLTHRU */ 4865 case case_QUIT: 4866 count = 0; 4867 c = KEY_EXIT; 4868 break; 4869 default: 4870 if (c >= '0' && c <= '9') { 4871 count = count * 10 + (c - '0'); 4872 continue; 4873 } 4874 break; 4875 } 4876 last = c; 4877 break; 4878 } 4879 if (count > 0) 4880 count--; 4881 } 4882 return (last); 4883} 4884 4885#define PAD_HIGH 200 4886#define PAD_WIDE 200 4887 4888static void 4889demo_pad(void) 4890/* Demonstrate pads. */ 4891{ 4892 WINDOW *panpad = newpad(PAD_HIGH, PAD_WIDE); 4893 4894 if (panpad == 0) { 4895 Cannot("cannot create requested pad"); 4896 return; 4897 } 4898 4899 fill_pad(panpad, FALSE); 4900 4901 panner_legend(LINES - 4); 4902 panner_legend(LINES - 3); 4903 panner_legend(LINES - 2); 4904 panner_legend(LINES - 1); 4905 4906 keypad(panpad, TRUE); 4907 4908 /* Make the pad (initially) narrow enough that a trace file won't wrap. 4909 * We'll still be able to widen it during a test, since that's required 4910 * for testing boundaries. 4911 */ 4912 panner(panpad, 2, 2, LINES - 5, COLS - 15, padgetch); 4913 4914 delwin(panpad); 4915 endwin(); 4916 erase(); 4917} 4918 4919/**************************************************************************** 4920 * 4921 * Tests from John Burnell's PDCurses tester 4922 * 4923 ****************************************************************************/ 4924 4925static void 4926Continue(WINDOW *win) 4927{ 4928 noecho(); 4929 wmove(win, 10, 1); 4930 mvwaddstr(win, 10, 1, " Press any key to continue"); 4931 wrefresh(win); 4932 wGetchar(win); 4933} 4934 4935static void 4936flushinp_test(WINDOW *win) 4937/* Input test, adapted from John Burnell's PDCurses tester */ 4938{ 4939 int w, h, bx, by, sw, sh, i; 4940 4941 WINDOW *subWin; 4942 wclear(win); 4943 4944 getmaxyx(win, h, w); 4945 getbegyx(win, by, bx); 4946 sw = w / 3; 4947 sh = h / 3; 4948 if ((subWin = subwin(win, sh, sw, by + h - sh - 2, bx + w - sw - 2)) == 0) 4949 return; 4950 4951#ifdef A_COLOR 4952 if (use_colors) { 4953 init_pair(2, COLOR_CYAN, COLOR_BLUE); 4954 wbkgd(subWin, COLOR_PAIR(2) | ' '); 4955 } 4956#endif 4957 wattrset(subWin, A_BOLD); 4958 box(subWin, ACS_VLINE, ACS_HLINE); 4959 mvwaddstr(subWin, 2, 1, "This is a subwindow"); 4960 wrefresh(win); 4961 4962 /* 4963 * This used to set 'nocbreak()'. However, Alexander Lukyanov says that 4964 * it only happened to "work" on SVr4 because that implementation does not 4965 * emulate nocbreak+noecho mode, whereas ncurses does. To get the desired 4966 * test behavior, we're using 'cbreak()', which will allow a single 4967 * character to return without needing a newline. - T.Dickey 1997/10/11. 4968 */ 4969 cbreak(); 4970 mvwaddstr(win, 0, 1, "This is a test of the flushinp() call."); 4971 4972 mvwaddstr(win, 2, 1, "Type random keys for 5 seconds."); 4973 mvwaddstr(win, 3, 1, 4974 "These should be discarded (not echoed) after the subwindow goes away."); 4975 wrefresh(win); 4976 4977 for (i = 0; i < 5; i++) { 4978 mvwprintw(subWin, 1, 1, "Time = %d", i); 4979 wrefresh(subWin); 4980 napms(1000); 4981 flushinp(); 4982 } 4983 4984 delwin(subWin); 4985 werase(win); 4986 flash(); 4987 wrefresh(win); 4988 napms(1000); 4989 4990 mvwaddstr(win, 2, 1, 4991 "If you were still typing when the window timer expired,"); 4992 mvwaddstr(win, 3, 1, 4993 "or else you typed nothing at all while it was running,"); 4994 mvwaddstr(win, 4, 1, 4995 "test was invalid. You'll see garbage or nothing at all. "); 4996 mvwaddstr(win, 6, 1, "Press a key"); 4997 wmove(win, 9, 10); 4998 wrefresh(win); 4999 echo(); 5000 wGetchar(win); 5001 flushinp(); 5002 mvwaddstr(win, 12, 0, 5003 "If you see any key other than what you typed, flushinp() is broken."); 5004 Continue(win); 5005 5006 wmove(win, 9, 10); 5007 wdelch(win); 5008 wrefresh(win); 5009 wmove(win, 12, 0); 5010 clrtoeol(); 5011 waddstr(win, 5012 "What you typed should now have been deleted; if not, wdelch() failed."); 5013 Continue(win); 5014 5015 cbreak(); 5016} 5017 5018/**************************************************************************** 5019 * 5020 * Menu test 5021 * 5022 ****************************************************************************/ 5023 5024#if USE_LIBMENU 5025 5026#define MENU_Y 8 5027#define MENU_X 8 5028 5029static int 5030menu_virtualize(int c) 5031{ 5032 if (c == '\n' || c == KEY_EXIT) 5033 return (MAX_COMMAND + 1); 5034 else if (c == 'u') 5035 return (REQ_SCR_ULINE); 5036 else if (c == 'd') 5037 return (REQ_SCR_DLINE); 5038 else if (c == 'b' || c == KEY_NPAGE) 5039 return (REQ_SCR_UPAGE); 5040 else if (c == 'f' || c == KEY_PPAGE) 5041 return (REQ_SCR_DPAGE); 5042 else if (c == 'n' || c == KEY_DOWN) 5043 return (REQ_NEXT_ITEM); 5044 else if (c == 'p' || c == KEY_UP) 5045 return (REQ_PREV_ITEM); 5046 else if (c == ' ') 5047 return (REQ_TOGGLE_ITEM); 5048 else { 5049 if (c != KEY_MOUSE) 5050 beep(); 5051 return (c); 5052 } 5053} 5054 5055static CONST_MENUS char *animals[] = 5056{ 5057 "Lions", 5058 "Tigers", 5059 "Bears", 5060 "(Oh my!)", 5061 "Newts", 5062 "Platypi", 5063 "Lemurs", 5064 "(Oh really?!)", 5065 "Leopards", 5066 "Panthers", 5067 "Pumas", 5068 "Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs", 5069 "Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs, Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs", 5070 (char *) 0 5071}; 5072 5073static void 5074menu_test(void) 5075{ 5076 MENU *m; 5077 ITEM *items[SIZEOF(animals)]; 5078 ITEM **ip = items; 5079 CONST_MENUS char **ap; 5080 int mrows, mcols, c; 5081 WINDOW *menuwin; 5082 5083#ifdef NCURSES_MOUSE_VERSION 5084 mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0); 5085#endif 5086 mvaddstr(0, 0, "This is the menu test:"); 5087 mvaddstr(2, 0, " Use up and down arrow to move the select bar."); 5088 mvaddstr(3, 0, " 'n' and 'p' act like arrows."); 5089 mvaddstr(4, 0, 5090 " 'b' and 'f' scroll up/down (page), 'u' and 'd' (line)."); 5091 mvaddstr(5, 0, " Press return to exit."); 5092 refresh(); 5093 5094 for (ap = animals; *ap; ap++) { 5095 if ((*ip = new_item(*ap, "")) != 0) 5096 ++ip; 5097 } 5098 *ip = (ITEM *) 0; 5099 5100 m = new_menu(items); 5101 5102 set_menu_format(m, (SIZEOF(animals) + 1) / 2, 1); 5103 scale_menu(m, &mrows, &mcols); 5104 5105 menuwin = newwin(mrows + 2, mcols + 2, MENU_Y, MENU_X); 5106 set_menu_win(m, menuwin); 5107 keypad(menuwin, TRUE); 5108 box(menuwin, 0, 0); 5109 5110 set_menu_sub(m, derwin(menuwin, mrows, mcols, 1, 1)); 5111 5112 post_menu(m); 5113 5114 while ((c = menu_driver(m, menu_virtualize(wGetchar(menuwin)))) != E_UNKNOWN_COMMAND) { 5115 if (c == E_NOT_POSTED) 5116 break; 5117 if (c == E_REQUEST_DENIED) 5118 beep(); 5119 continue; 5120 } 5121 5122 (void) mvprintw(LINES - 2, 0, 5123 "You chose: %s\n", item_name(current_item(m))); 5124 (void) addstr("Press any key to continue..."); 5125 wGetchar(stdscr); 5126 5127 unpost_menu(m); 5128 delwin(menuwin); 5129 5130 free_menu(m); 5131 for (ip = items; *ip; ip++) 5132 free_item(*ip); 5133#ifdef NCURSES_MOUSE_VERSION 5134 mousemask(0, (mmask_t *) 0); 5135#endif 5136} 5137 5138#ifdef TRACE 5139#define T_TBL(name) { #name, name } 5140static struct { 5141 const char *name; 5142 unsigned mask; 5143} t_tbl[] = { 5144 5145 T_TBL(TRACE_DISABLE), 5146 T_TBL(TRACE_TIMES), 5147 T_TBL(TRACE_TPUTS), 5148 T_TBL(TRACE_UPDATE), 5149 T_TBL(TRACE_MOVE), 5150 T_TBL(TRACE_CHARPUT), 5151 T_TBL(TRACE_ORDINARY), 5152 T_TBL(TRACE_CALLS), 5153 T_TBL(TRACE_VIRTPUT), 5154 T_TBL(TRACE_IEVENT), 5155 T_TBL(TRACE_BITS), 5156 T_TBL(TRACE_ICALLS), 5157 T_TBL(TRACE_CCALLS), 5158 T_TBL(TRACE_DATABASE), 5159 T_TBL(TRACE_ATTRS), 5160 T_TBL(TRACE_MAXIMUM), 5161 { 5162 (char *) 0, 0 5163 } 5164}; 5165 5166static char * 5167tracetrace(unsigned tlevel) 5168{ 5169 static char *buf; 5170 int n; 5171 5172 if (buf == 0) { 5173 size_t need = 12; 5174 for (n = 0; t_tbl[n].name != 0; n++) 5175 need += strlen(t_tbl[n].name) + 2; 5176 buf = typeMalloc(char, need); 5177 } 5178 sprintf(buf, "0x%02x = {", tlevel); 5179 if (tlevel == 0) { 5180 sprintf(buf + strlen(buf), "%s, ", t_tbl[0].name); 5181 } else { 5182 for (n = 1; t_tbl[n].name != 0; n++) 5183 if ((tlevel & t_tbl[n].mask) == t_tbl[n].mask) { 5184 strcat(buf, t_tbl[n].name); 5185 strcat(buf, ", "); 5186 } 5187 } 5188 if (buf[strlen(buf) - 2] == ',') 5189 buf[strlen(buf) - 2] = '\0'; 5190 return (strcat(buf, "}")); 5191} 5192 5193/* fake a dynamically reconfigurable menu using the 0th entry to deselect 5194 * the others 5195 */ 5196static int 5197run_trace_menu(MENU * m) 5198{ 5199 ITEM **items; 5200 ITEM *i, **p; 5201 5202 for (;;) { 5203 bool changed = FALSE; 5204 switch (menu_driver(m, menu_virtualize(wGetchar(menu_win(m))))) { 5205 case E_UNKNOWN_COMMAND: 5206 return FALSE; 5207 default: 5208 items = menu_items(m); 5209 i = current_item(m); 5210 if (i == items[0]) { 5211 if (item_value(i)) { 5212 for (p = items + 1; *p != 0; p++) 5213 if (item_value(*p)) { 5214 set_item_value(*p, FALSE); 5215 changed = TRUE; 5216 } 5217 } 5218 } else { 5219 for (p = items + 1; *p != 0; p++) 5220 if (item_value(*p)) { 5221 set_item_value(items[0], FALSE); 5222 changed = TRUE; 5223 break; 5224 } 5225 } 5226 if (!changed) 5227 return TRUE; 5228 } 5229 } 5230} 5231 5232static void 5233trace_set(void) 5234/* interactively set the trace level */ 5235{ 5236 MENU *m; 5237 ITEM *items[SIZEOF(t_tbl)]; 5238 ITEM **ip = items; 5239 int mrows, mcols; 5240 unsigned newtrace; 5241 int n; 5242 WINDOW *menuwin; 5243 5244 mvaddstr(0, 0, "Interactively set trace level:"); 5245 mvaddstr(2, 0, " Press space bar to toggle a selection."); 5246 mvaddstr(3, 0, " Use up and down arrow to move the select bar."); 5247 mvaddstr(4, 0, " Press return to set the trace level."); 5248 mvprintw(6, 0, "(Current trace level is %s)", tracetrace(_nc_tracing)); 5249 5250 refresh(); 5251 5252 for (n = 0; t_tbl[n].name != 0; n++) { 5253 if ((*ip = new_item(t_tbl[n].name, "")) != 0) { 5254 ++ip; 5255 } 5256 } 5257 *ip = (ITEM *) 0; 5258 5259 m = new_menu(items); 5260 5261 set_menu_format(m, 0, 2); 5262 scale_menu(m, &mrows, &mcols); 5263 5264 menu_opts_off(m, O_ONEVALUE); 5265 menuwin = newwin(mrows + 2, mcols + 2, MENU_Y, MENU_X); 5266 set_menu_win(m, menuwin); 5267 keypad(menuwin, TRUE); 5268 box(menuwin, 0, 0); 5269 5270 set_menu_sub(m, derwin(menuwin, mrows, mcols, 1, 1)); 5271 5272 post_menu(m); 5273 5274 for (ip = menu_items(m); *ip; ip++) { 5275 unsigned mask = t_tbl[item_index(*ip)].mask; 5276 if (mask == 0) 5277 set_item_value(*ip, _nc_tracing == 0); 5278 else if ((mask & _nc_tracing) == mask) 5279 set_item_value(*ip, TRUE); 5280 } 5281 5282 while (run_trace_menu(m)) 5283 continue; 5284 5285 newtrace = 0; 5286 for (ip = menu_items(m); *ip; ip++) 5287 if (item_value(*ip)) 5288 newtrace |= t_tbl[item_index(*ip)].mask; 5289 trace(newtrace); 5290 Trace(("trace level interactively set to %s", tracetrace(_nc_tracing))); 5291 5292 (void) mvprintw(LINES - 2, 0, 5293 "Trace level is %s\n", tracetrace(_nc_tracing)); 5294 (void) addstr("Press any key to continue..."); 5295 wGetchar(stdscr); 5296 5297 unpost_menu(m); 5298 delwin(menuwin); 5299 5300 free_menu(m); 5301 for (ip = items; *ip; ip++) 5302 free_item(*ip); 5303} 5304#endif /* TRACE */ 5305#endif /* USE_LIBMENU */ 5306 5307/**************************************************************************** 5308 * 5309 * Forms test 5310 * 5311 ****************************************************************************/ 5312#if USE_LIBFORM 5313static FIELD * 5314make_label(int frow, int fcol, NCURSES_CONST char *label) 5315{ 5316 FIELD *f = new_field(1, (int) strlen(label), frow, fcol, 0, 0); 5317 5318 if (f) { 5319 set_field_buffer(f, 0, label); 5320 set_field_opts(f, (int) (field_opts(f) & ~O_ACTIVE)); 5321 } 5322 return (f); 5323} 5324 5325static FIELD * 5326make_field(int frow, int fcol, int rows, int cols, bool secure) 5327{ 5328 FIELD *f = new_field(rows, cols, frow, fcol, 0, secure ? 1 : 0); 5329 5330 if (f) { 5331 set_field_back(f, A_UNDERLINE); 5332 set_field_userptr(f, (void *) 0); 5333 } 5334 return (f); 5335} 5336 5337static void 5338display_form(FORM * f) 5339{ 5340 WINDOW *w; 5341 int rows, cols; 5342 5343 scale_form(f, &rows, &cols); 5344 5345 if ((w = newwin(rows + 2, cols + 4, 0, 0)) != (WINDOW *) 0) { 5346 set_form_win(f, w); 5347 set_form_sub(f, derwin(w, rows, cols, 1, 2)); 5348 box(w, 0, 0); 5349 keypad(w, TRUE); 5350 } 5351 5352 if (post_form(f) != E_OK) 5353 wrefresh(w); 5354} 5355 5356static void 5357erase_form(FORM * f) 5358{ 5359 WINDOW *w = form_win(f); 5360 WINDOW *s = form_sub(f); 5361 5362 unpost_form(f); 5363 werase(w); 5364 wrefresh(w); 5365 delwin(s); 5366 delwin(w); 5367} 5368 5369static int 5370edit_secure(FIELD * me, int c) 5371{ 5372 int rows, cols, frow, fcol, nrow, nbuf; 5373 5374 if (field_info(me, &rows, &cols, &frow, &fcol, &nrow, &nbuf) == E_OK 5375 && nbuf > 0) { 5376 char *source = field_buffer(me, 1); 5377 char temp[80]; 5378 long len; 5379 5380 strcpy(temp, source ? source : ""); 5381 len = (long) (char *) field_userptr(me); 5382 if (c <= KEY_MAX) { 5383 if (isgraph(c) && (len + 1) < (int) sizeof(temp)) { 5384 temp[len++] = (char) c; 5385 temp[len] = 0; 5386 set_field_buffer(me, 1, temp); 5387 c = '*'; 5388 } else { 5389 c = 0; 5390 } 5391 } else { 5392 switch (c) { 5393 case REQ_BEG_FIELD: 5394 case REQ_CLR_EOF: 5395 case REQ_CLR_EOL: 5396 case REQ_DEL_LINE: 5397 case REQ_DEL_WORD: 5398 case REQ_DOWN_CHAR: 5399 case REQ_END_FIELD: 5400 case REQ_INS_CHAR: 5401 case REQ_INS_LINE: 5402 case REQ_LEFT_CHAR: 5403 case REQ_NEW_LINE: 5404 case REQ_NEXT_WORD: 5405 case REQ_PREV_WORD: 5406 case REQ_RIGHT_CHAR: 5407 case REQ_UP_CHAR: 5408 c = 0; /* we don't want to do inline editing */ 5409 break; 5410 case REQ_CLR_FIELD: 5411 if (len) { 5412 temp[0] = 0; 5413 set_field_buffer(me, 1, temp); 5414 } 5415 break; 5416 case REQ_DEL_CHAR: 5417 case REQ_DEL_PREV: 5418 if (len) { 5419 temp[--len] = 0; 5420 set_field_buffer(me, 1, temp); 5421 } 5422 break; 5423 } 5424 } 5425 set_field_userptr(me, (void *) len); 5426 } 5427 return c; 5428} 5429 5430static int 5431form_virtualize(FORM * f, WINDOW *w) 5432{ 5433 /* *INDENT-OFF* */ 5434 static const struct { 5435 int code; 5436 int result; 5437 } lookup[] = { 5438 { CTRL('A'), REQ_NEXT_CHOICE }, 5439 { CTRL('B'), REQ_PREV_WORD }, 5440 { CTRL('C'), REQ_CLR_EOL }, 5441 { CTRL('D'), REQ_DOWN_FIELD }, 5442 { CTRL('E'), REQ_END_FIELD }, 5443 { CTRL('F'), REQ_NEXT_PAGE }, 5444 { CTRL('G'), REQ_DEL_WORD }, 5445 { CTRL('H'), REQ_DEL_PREV }, 5446 { CTRL('I'), REQ_INS_CHAR }, 5447 { CTRL('K'), REQ_CLR_EOF }, 5448 { CTRL('L'), REQ_LEFT_FIELD }, 5449 { CTRL('M'), REQ_NEW_LINE }, 5450 { CTRL('N'), REQ_NEXT_FIELD }, 5451 { CTRL('O'), REQ_INS_LINE }, 5452 { CTRL('P'), REQ_PREV_FIELD }, 5453 { CTRL('R'), REQ_RIGHT_FIELD }, 5454 { CTRL('S'), REQ_BEG_FIELD }, 5455 { CTRL('U'), REQ_UP_FIELD }, 5456 { CTRL('V'), REQ_DEL_CHAR }, 5457 { CTRL('W'), REQ_NEXT_WORD }, 5458 { CTRL('X'), REQ_CLR_FIELD }, 5459 { CTRL('Y'), REQ_DEL_LINE }, 5460 { CTRL('Z'), REQ_PREV_CHOICE }, 5461 { ESCAPE, MAX_FORM_COMMAND + 1 }, 5462 { KEY_BACKSPACE, REQ_DEL_PREV }, 5463 { KEY_DOWN, REQ_DOWN_CHAR }, 5464 { KEY_END, REQ_LAST_FIELD }, 5465 { KEY_HOME, REQ_FIRST_FIELD }, 5466 { KEY_LEFT, REQ_LEFT_CHAR }, 5467 { KEY_LL, REQ_LAST_FIELD }, 5468 { KEY_NEXT, REQ_NEXT_FIELD }, 5469 { KEY_NPAGE, REQ_NEXT_PAGE }, 5470 { KEY_PPAGE, REQ_PREV_PAGE }, 5471 { KEY_PREVIOUS, REQ_PREV_FIELD }, 5472 { KEY_RIGHT, REQ_RIGHT_CHAR }, 5473 { KEY_UP, REQ_UP_CHAR }, 5474 { QUIT, MAX_FORM_COMMAND + 1 } 5475 }; 5476 /* *INDENT-ON* */ 5477 5478 static int mode = REQ_INS_MODE; 5479 int c = wGetchar(w); 5480 unsigned n; 5481 FIELD *me = current_field(f); 5482 bool current = TRUE; 5483 5484 if (c == CTRL(']')) { 5485 if (mode == REQ_INS_MODE) { 5486 mode = REQ_OVL_MODE; 5487 } else { 5488 mode = REQ_INS_MODE; 5489 } 5490 c = mode; 5491 } else { 5492 for (n = 0; n < SIZEOF(lookup); n++) { 5493 if (lookup[n].code == c) { 5494 c = lookup[n].result; 5495 break; 5496 } 5497 } 5498 } 5499 mvprintw(0, COLS - 6, "(%s)", mode == REQ_INS_MODE ? "INS" : "OVL"); 5500 5501 /* 5502 * Force the field that the user is typing into to be in reverse video, 5503 * while the other fields are shown underlined. 5504 */ 5505 switch (c) { 5506 case REQ_BEG_FIELD: 5507 case REQ_CLR_EOF: 5508 case REQ_CLR_EOL: 5509 case REQ_CLR_FIELD: 5510 case REQ_DEL_CHAR: 5511 case REQ_DEL_LINE: 5512 case REQ_DEL_PREV: 5513 case REQ_DEL_WORD: 5514 case REQ_END_FIELD: 5515 case REQ_INS_CHAR: 5516 case REQ_INS_LINE: 5517 case REQ_LEFT_CHAR: 5518 case REQ_LEFT_FIELD: 5519 case REQ_NEXT_WORD: 5520 case REQ_RIGHT_CHAR: 5521 current = TRUE; 5522 break; 5523 default: 5524 current = (c < KEY_MAX); 5525 break; 5526 } 5527 if (current) { 5528 c = edit_secure(me, c); 5529 set_field_back(me, A_REVERSE); 5530 } else { 5531 c = edit_secure(me, c); 5532 set_field_back(me, A_UNDERLINE); 5533 } 5534 return c; 5535} 5536 5537static int 5538my_form_driver(FORM * form, int c) 5539{ 5540 if (c == (MAX_FORM_COMMAND + 1) 5541 && form_driver(form, REQ_VALIDATION) == E_OK) 5542 return (TRUE); 5543 else { 5544 beep(); 5545 return (FALSE); 5546 } 5547} 5548 5549#ifdef NCURSES_VERSION 5550#define FIELDCHECK_CB(func) bool func(FIELD * fld, const void * data GCC_UNUSED) 5551#define CHAR_CHECK_CB(func) bool func(int ch, const void *data GCC_UNUSED) 5552#else 5553#define FIELDCHECK_CB(func) int func(FIELD * fld, char * data GCC_UNUSED) 5554#define CHAR_CHECK_CB(func) int func(int ch, char *data GCC_UNUSED) 5555#endif 5556 5557/* 5558 * Allow a middle initial, optionally with a '.' to end it. 5559 */ 5560static 5561FIELDCHECK_CB(mi_field_check) 5562{ 5563 char *s = field_buffer(fld, 0); 5564 int state = 0; 5565 int n; 5566 5567 for (n = 0; s[n] != '\0'; ++n) { 5568 switch (state) { 5569 case 0: 5570 if (s[n] == '.') { 5571 if (n != 1) 5572 return FALSE; 5573 state = 2; 5574 } else if (isspace(UChar(s[n]))) { 5575 state = 2; 5576 } 5577 break; 5578 case 2: 5579 if (!isspace(UChar(s[n]))) 5580 return FALSE; 5581 break; 5582 } 5583 } 5584 5585 /* force the form to display a leading capital */ 5586 if (islower(UChar(s[0]))) { 5587 s[0] = (char) toupper(UChar(s[0])); 5588 set_field_buffer(fld, 0, s); 5589 } 5590 return TRUE; 5591} 5592 5593static 5594CHAR_CHECK_CB(mi_char_check) 5595{ 5596 return ((isalpha(ch) || ch == '.') ? TRUE : FALSE); 5597} 5598 5599/* 5600 * Passwords should be at least 6 characters. 5601 */ 5602static 5603FIELDCHECK_CB(pw_field_check) 5604{ 5605 char *s = field_buffer(fld, 0); 5606 int n; 5607 5608 for (n = 0; s[n] != '\0'; ++n) { 5609 if (isspace(UChar(s[n]))) { 5610 if (n < 6) 5611 return FALSE; 5612 } 5613 } 5614 return TRUE; 5615} 5616 5617static 5618CHAR_CHECK_CB(pw_char_check) 5619{ 5620 return (isgraph(ch) ? TRUE : FALSE); 5621} 5622 5623static void 5624demo_forms(void) 5625{ 5626 WINDOW *w; 5627 FORM *form; 5628 FIELD *f[12], *secure; 5629 FIELDTYPE *fty_middle = new_fieldtype(mi_field_check, mi_char_check); 5630 FIELDTYPE *fty_passwd = new_fieldtype(pw_field_check, pw_char_check); 5631 int finished = 0, c; 5632 unsigned n = 0; 5633 5634#ifdef NCURSES_MOUSE_VERSION 5635 mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0); 5636#endif 5637 5638 move(18, 0); 5639 addstr("Defined edit/traversal keys: ^Q/ESC- exit form\n"); 5640 addstr("^N -- go to next field ^P -- go to previous field\n"); 5641 addstr("Home -- go to first field End -- go to last field\n"); 5642 addstr("^L -- go to field to left ^R -- go to field to right\n"); 5643 addstr("^U -- move upward to field ^D -- move downward to field\n"); 5644 addstr("^W -- go to next word ^B -- go to previous word\n"); 5645 addstr("^S -- go to start of field ^E -- go to end of field\n"); 5646 addstr("^H -- delete previous char ^Y -- delete line\n"); 5647 addstr("^G -- delete current word ^C -- clear to end of line\n"); 5648 addstr("^K -- clear to end of field ^X -- clear field\n"); 5649 addstr("Arrow keys move within a field as you would expect. ^] toggles overlay mode."); 5650 5651 mvaddstr(4, 57, "Forms Entry Test"); 5652 5653 refresh(); 5654 5655 /* describe the form */ 5656 memset(f, 0, sizeof(f)); 5657 f[n++] = make_label(0, 15, "Sample Form"); 5658 5659 f[n++] = make_label(2, 0, "Last Name"); 5660 f[n++] = make_field(3, 0, 1, 18, FALSE); 5661 set_field_type(f[n - 1], TYPE_ALPHA, 1); 5662 5663 f[n++] = make_label(2, 20, "First Name"); 5664 f[n++] = make_field(3, 20, 1, 12, FALSE); 5665 set_field_type(f[n - 1], TYPE_ALPHA, 1); 5666 5667 f[n++] = make_label(2, 34, "Middle Name"); 5668 f[n++] = make_field(3, 34, 1, 12, FALSE); 5669 set_field_type(f[n - 1], fty_middle); 5670 5671 f[n++] = make_label(5, 0, "Comments"); 5672 f[n++] = make_field(6, 0, 4, 46, FALSE); 5673 5674 f[n++] = make_label(5, 20, "Password:"); 5675 secure = 5676 f[n++] = make_field(5, 30, 1, 9, TRUE); 5677 set_field_type(f[n - 1], fty_passwd); 5678 f[n++] = (FIELD *) 0; 5679 5680 if ((form = new_form(f)) != 0) { 5681 5682 display_form(form); 5683 5684 w = form_win(form); 5685 raw(); 5686 nonl(); /* lets us read ^M's */ 5687 while (!finished) { 5688 switch (form_driver(form, c = form_virtualize(form, w))) { 5689 case E_OK: 5690 mvaddstr(5, 57, field_buffer(secure, 1)); 5691 clrtoeol(); 5692 refresh(); 5693 break; 5694 case E_UNKNOWN_COMMAND: 5695 finished = my_form_driver(form, c); 5696 break; 5697 default: 5698 beep(); 5699 break; 5700 } 5701 } 5702 5703 erase_form(form); 5704 5705 free_form(form); 5706 } 5707 for (c = 0; f[c] != 0; c++) 5708 free_field(f[c]); 5709 free_fieldtype(fty_middle); 5710 free_fieldtype(fty_passwd); 5711 noraw(); 5712 nl(); 5713 5714#ifdef NCURSES_MOUSE_VERSION 5715 mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0); 5716#endif 5717} 5718#endif /* USE_LIBFORM */ 5719 5720/**************************************************************************** 5721 * 5722 * Overlap test 5723 * 5724 ****************************************************************************/ 5725 5726static void 5727fillwin(WINDOW *win, char ch) 5728{ 5729 int y, x; 5730 int y1, x1; 5731 5732 getmaxyx(win, y1, x1); 5733 for (y = 0; y < y1; y++) { 5734 wmove(win, y, 0); 5735 for (x = 0; x < x1; x++) 5736 waddch(win, UChar(ch)); 5737 } 5738} 5739 5740static void 5741crosswin(WINDOW *win, char ch) 5742{ 5743 int y, x; 5744 int y1, x1; 5745 5746 getmaxyx(win, y1, x1); 5747 for (y = 0; y < y1; y++) { 5748 for (x = 0; x < x1; x++) 5749 if (((x > (x1 - 1) / 3) && (x <= (2 * (x1 - 1)) / 3)) 5750 || (((y > (y1 - 1) / 3) && (y <= (2 * (y1 - 1)) / 3)))) { 5751 wmove(win, y, x); 5752 waddch(win, UChar(ch)); 5753 } 5754 } 5755} 5756 5757#define OVERLAP_FLAVORS 5 5758 5759static void 5760overlap_helpitem(int state, int item, char *message) 5761{ 5762 int row = (item / 2); 5763 int col = ((item % 2) ? COLS / 2 : 0); 5764 5765 move(LINES - 6 + row, col); 5766 printw("%c%c = %s", state == row ? '>' : ' ', 'a' + item, message); 5767 clrtoeol(); 5768} 5769 5770static void 5771overlap_test_1_attr(WINDOW *win, int flavor, int col) 5772{ 5773 short cpair = (short) (1 + (flavor * 2) + col); 5774 5775 switch (flavor) { 5776 case 0: 5777 wattrset(win, A_NORMAL); 5778 break; 5779 case 1: 5780 wattrset(win, A_BOLD); 5781 break; 5782 case 2: 5783 init_pair(cpair, COLOR_BLUE, COLOR_WHITE); 5784 wattrset(win, COLOR_PAIR(cpair) | A_NORMAL); 5785 break; 5786 case 3: 5787 init_pair(cpair, COLOR_WHITE, COLOR_BLUE); 5788 wattrset(win, COLOR_PAIR(cpair) | A_BOLD); 5789 break; 5790 } 5791} 5792 5793static void 5794overlap_test_2_attr(WINDOW *win, int flavor, int col) 5795{ 5796 short cpair = (short) (9 + (flavor * 2) + col); 5797 5798 switch (flavor) { 5799 case 0: 5800 /* no effect */ 5801 break; 5802 case 1: 5803 /* no effect */ 5804 break; 5805 case 2: 5806 init_pair(cpair, COLOR_RED, COLOR_GREEN); 5807 wbkgdset(win, ' ' | A_BLINK | COLOR_PAIR(cpair)); 5808 break; 5809 case 3: 5810 wbkgdset(win, ' ' | A_NORMAL); 5811 break; 5812 } 5813} 5814 5815static int 5816overlap_help(int state, int flavors[OVERLAP_FLAVORS]) 5817{ 5818 int row; 5819 int col; 5820 int item; 5821 const char *ths, *tht; 5822 char msg[80]; 5823 5824 if (state < 0) 5825 state += OVERLAP_FLAVORS; 5826 state = state % OVERLAP_FLAVORS; 5827 assert(state >= 0 && state < OVERLAP_FLAVORS); 5828 5829 for (item = 0; item < (2 * OVERLAP_FLAVORS); ++item) { 5830 row = item / 2; 5831 col = item % 2; 5832 ths = col ? "B" : "A"; 5833 tht = col ? "A" : "B"; 5834 5835 switch (row) { 5836 case 0: 5837 flavors[row] = 0; 5838 sprintf(msg, "refresh %s, then %s, then doupdate.", ths, tht); 5839 break; 5840 case 1: 5841 if (use_colors) { 5842 flavors[row] %= 4; 5843 } else { 5844 flavors[row] %= 2; 5845 } 5846 overlap_test_1_attr(stdscr, flavors[row], col); 5847 sprintf(msg, "fill window %s with letter %s.", ths, ths); 5848 break; 5849 case 2: 5850 if (use_colors) { 5851 flavors[row] %= 4; 5852 } else { 5853 flavors[row] %= 2; 5854 } 5855 switch (flavors[row]) { 5856 case 0: 5857 sprintf(msg, "cross pattern in window %s.", ths); 5858 break; 5859 case 1: 5860 sprintf(msg, "draw box in window %s.", ths); 5861 break; 5862 case 2: 5863 sprintf(msg, "set background of window %s.", ths); 5864 break; 5865 case 3: 5866 sprintf(msg, "reset background of window %s.", ths); 5867 break; 5868 } 5869 break; 5870 case 3: 5871 flavors[row] = 0; 5872 sprintf(msg, "clear window %s.", ths); 5873 break; 5874 case 4: 5875 flavors[row] %= 4; 5876 switch (flavors[row]) { 5877 case 0: 5878 sprintf(msg, "overwrite %s onto %s.", ths, tht); 5879 break; 5880 case 1: 5881 sprintf(msg, "copywin(FALSE) %s onto %s.", ths, tht); 5882 break; 5883 case 2: 5884 sprintf(msg, "copywin(TRUE) %s onto %s.", ths, tht); 5885 break; 5886 case 3: 5887 sprintf(msg, "overlay %s onto %s.", ths, tht); 5888 break; 5889 } 5890 break; 5891 } 5892 overlap_helpitem(state, item, msg); 5893 wattrset(stdscr, A_NORMAL); 5894 wbkgdset(stdscr, ' ' | A_NORMAL); 5895 } 5896 move(LINES - 1, 0); 5897 printw("^Q/ESC = terminate test. Up/down/space select test variations (%d %d).", 5898 state, flavors[state]); 5899 5900 return state; 5901} 5902 5903static void 5904overlap_test_0(WINDOW *a, WINDOW *b) 5905{ 5906 touchwin(a); 5907 touchwin(b); 5908 wnoutrefresh(a); 5909 wnoutrefresh(b); 5910 doupdate(); 5911} 5912 5913static void 5914overlap_test_1(int flavor, int col, WINDOW *a, char fill) 5915{ 5916 overlap_test_1_attr(a, flavor, col); 5917 fillwin(a, fill); 5918 wattrset(a, A_NORMAL); 5919} 5920 5921static void 5922overlap_test_2(int flavor, int col, WINDOW *a, char fill) 5923{ 5924 overlap_test_2_attr(a, flavor, col); 5925 switch (flavor) { 5926 case 0: 5927 crosswin(a, fill); 5928 break; 5929 case 1: 5930 box(a, 0, 0); 5931 break; 5932 case 2: 5933 /* done in overlap_test_2_attr */ 5934 break; 5935 case 3: 5936 /* done in overlap_test_2_attr */ 5937 break; 5938 } 5939} 5940 5941static void 5942overlap_test_3(WINDOW *a) 5943{ 5944 wclear(a); 5945 wmove(a, 0, 0); 5946} 5947 5948static void 5949overlap_test_4(int flavor, WINDOW *a, WINDOW *b) 5950{ 5951 switch (flavor) { 5952 case 0: 5953 overwrite(a, b); 5954 break; 5955 case 1: 5956 copywin(a, b, 0, 0, 0, 0, getmaxy(b), getmaxx(b), FALSE); 5957 break; 5958 case 2: 5959 copywin(a, b, 0, 0, 0, 0, getmaxy(b), getmaxx(b), TRUE); 5960 break; 5961 case 3: 5962 overlay(a, b); 5963 break; 5964 } 5965} 5966 5967/* test effects of overlapping windows */ 5968static void 5969overlap_test(void) 5970{ 5971 int ch; 5972 int state, flavor[OVERLAP_FLAVORS]; 5973 5974 WINDOW *win1 = newwin(9, 20, 3, 3); 5975 WINDOW *win2 = newwin(9, 20, 9, 16); 5976 5977 curs_set(0); 5978 raw(); 5979 refresh(); 5980 move(0, 0); 5981 printw("This test shows the behavior of wnoutrefresh() with respect to\n"); 5982 printw("the shared region of two overlapping windows A and B. The cross\n"); 5983 printw("pattern in each window does not overlap the other.\n"); 5984 5985 memset(flavor, 0, sizeof(flavor)); 5986 state = overlap_help(0, flavor); 5987 5988 while (!isQuit(ch = Getchar())) 5989 switch (ch) { 5990 case 'a': /* refresh window A first, then B */ 5991 overlap_test_0(win1, win2); 5992 break; 5993 5994 case 'b': /* refresh window B first, then A */ 5995 overlap_test_0(win2, win1); 5996 break; 5997 5998 case 'c': /* fill window A so it's visible */ 5999 overlap_test_1(flavor[1], 0, win1, 'A'); 6000 break; 6001 6002 case 'd': /* fill window B so it's visible */ 6003 overlap_test_1(flavor[1], 1, win2, 'B'); 6004 break; 6005 6006 case 'e': /* cross test pattern in window A */ 6007 overlap_test_2(flavor[2], 0, win1, 'A'); 6008 break; 6009 6010 case 'f': /* cross test pattern in window A */ 6011 overlap_test_2(flavor[2], 1, win2, 'B'); 6012 break; 6013 6014 case 'g': /* clear window A */ 6015 overlap_test_3(win1); 6016 break; 6017 6018 case 'h': /* clear window B */ 6019 overlap_test_3(win2); 6020 break; 6021 6022 case 'i': /* overwrite A onto B */ 6023 overlap_test_4(flavor[4], win1, win2); 6024 break; 6025 6026 case 'j': /* overwrite B onto A */ 6027 overlap_test_4(flavor[4], win2, win1); 6028 break; 6029 6030 case CTRL('n'): 6031 case KEY_DOWN: 6032 state = overlap_help(state + 1, flavor); 6033 break; 6034 6035 case CTRL('p'): 6036 case KEY_UP: 6037 state = overlap_help(state - 1, flavor); 6038 break; 6039 6040 case ' ': 6041 flavor[state] += 1; 6042 state = overlap_help(state, flavor); 6043 break; 6044 6045 case '?': 6046 state = overlap_help(state, flavor); 6047 break; 6048 6049 default: 6050 beep(); 6051 break; 6052 } 6053 6054 delwin(win2); 6055 delwin(win1); 6056 erase(); 6057 curs_set(1); 6058 endwin(); 6059} 6060 6061/**************************************************************************** 6062 * 6063 * Main sequence 6064 * 6065 ****************************************************************************/ 6066 6067static bool 6068do_single_test(const char c) 6069/* perform a single specified test */ 6070{ 6071 switch (c) { 6072 case 'a': 6073 getch_test(); 6074 break; 6075 6076#if USE_WIDEC_SUPPORT 6077 case 'A': 6078 get_wch_test(); 6079 break; 6080#endif 6081 6082 case 'b': 6083 attr_test(); 6084 break; 6085 6086#if USE_WIDEC_SUPPORT 6087 case 'B': 6088 wide_attr_test(); 6089 break; 6090#endif 6091 6092 case 'c': 6093 if (!use_colors) 6094 Cannot("does not support color."); 6095 else 6096 color_test(); 6097 break; 6098 6099#if USE_WIDEC_SUPPORT 6100 case 'C': 6101 if (!use_colors) 6102 Cannot("does not support color."); 6103 else 6104 wide_color_test(); 6105 break; 6106#endif 6107 6108 case 'd': 6109 if (!use_colors) 6110 Cannot("does not support color."); 6111 else if (!can_change_color()) 6112 Cannot("has hardwired color values."); 6113 else 6114 color_edit(); 6115 break; 6116 6117#if USE_SOFTKEYS 6118 case 'e': 6119 slk_test(); 6120 break; 6121#endif 6122 6123#if USE_WIDEC_SUPPORT 6124 case 'E': 6125 wide_slk_test(); 6126 break; 6127#endif 6128 case 'f': 6129 acs_display(); 6130 break; 6131 6132#if USE_WIDEC_SUPPORT 6133 case 'F': 6134 wide_acs_display(); 6135 break; 6136#endif 6137 6138#if USE_LIBPANEL 6139 case 'o': 6140 demo_panels(init_panel, fill_panel); 6141 break; 6142#endif 6143 6144#if USE_WIDEC_SUPPORT && USE_LIBPANEL 6145 case 'O': 6146 demo_panels(init_wide_panel, fill_wide_panel); 6147 break; 6148#endif 6149 6150 case 'g': 6151 acs_and_scroll(); 6152 break; 6153 6154 case 'i': 6155 flushinp_test(stdscr); 6156 break; 6157 6158 case 'k': 6159 test_sgr_attributes(); 6160 break; 6161 6162#if USE_LIBMENU 6163 case 'm': 6164 menu_test(); 6165 break; 6166#endif 6167 6168 case 'p': 6169 demo_pad(); 6170 break; 6171 6172#if USE_LIBFORM 6173 case 'r': 6174 demo_forms(); 6175 break; 6176#endif 6177 6178 case 's': 6179 overlap_test(); 6180 break; 6181 6182#if USE_LIBMENU && defined(TRACE) 6183 case 't': 6184 trace_set(); 6185 break; 6186#endif 6187 6188 case '?': 6189 break; 6190 6191 default: 6192 return FALSE; 6193 } 6194 6195 return TRUE; 6196} 6197 6198static void 6199usage(void) 6200{ 6201 static const char *const tbl[] = 6202 { 6203 "Usage: ncurses [options]" 6204 ,"" 6205 ,"Options:" 6206#ifdef NCURSES_VERSION 6207 ," -a f,b set default-colors (assumed white-on-black)" 6208 ," -d use default-colors if terminal supports them" 6209#endif 6210#if USE_SOFTKEYS 6211 ," -e fmt specify format for soft-keys test (e)" 6212#endif 6213#if HAVE_RIPOFFLINE 6214 ," -f rip-off footer line (can repeat)" 6215 ," -h rip-off header line (can repeat)" 6216#endif 6217 ," -m do not use colors" 6218 ," -p file rgb values to use in 'd' rather than ncurses's builtin" 6219#if USE_LIBPANEL 6220 ," -s msec specify nominal time for panel-demo (default: 1, to hold)" 6221#endif 6222#ifdef TRACE 6223 ," -t mask specify default trace-level (may toggle with ^T)" 6224#endif 6225 }; 6226 size_t n; 6227 for (n = 0; n < SIZEOF(tbl); n++) 6228 fprintf(stderr, "%s\n", tbl[n]); 6229 ExitProgram(EXIT_FAILURE); 6230} 6231 6232static void 6233set_terminal_modes(void) 6234{ 6235 noraw(); 6236 cbreak(); 6237 noecho(); 6238 scrollok(stdscr, TRUE); 6239 idlok(stdscr, TRUE); 6240 keypad(stdscr, TRUE); 6241} 6242 6243#ifdef SIGUSR1 6244static RETSIGTYPE 6245announce_sig(int sig) 6246{ 6247 (void) fprintf(stderr, "Handled signal %d\r\n", sig); 6248} 6249#endif 6250 6251#if HAVE_RIPOFFLINE 6252static int 6253rip_footer(WINDOW *win, int cols) 6254{ 6255 wbkgd(win, A_REVERSE); 6256 werase(win); 6257 wmove(win, 0, 0); 6258 wprintw(win, "footer: window %p, %d columns", win, cols); 6259 wnoutrefresh(win); 6260 return OK; 6261} 6262 6263static int 6264rip_header(WINDOW *win, int cols) 6265{ 6266 wbkgd(win, A_REVERSE); 6267 werase(win); 6268 wmove(win, 0, 0); 6269 wprintw(win, "header: window %p, %d columns", win, cols); 6270 wnoutrefresh(win); 6271 return OK; 6272} 6273#endif /* HAVE_RIPOFFLINE */ 6274 6275static void 6276main_menu(bool top) 6277{ 6278 char command; 6279 6280 do { 6281 (void) puts("This is the ncurses main menu"); 6282 (void) puts("a = keyboard and mouse input test"); 6283#if USE_WIDEC_SUPPORT 6284 (void) puts("A = wide-character keyboard and mouse input test"); 6285#endif 6286 (void) puts("b = character attribute test"); 6287#if USE_WIDEC_SUPPORT 6288 (void) puts("B = wide-character attribute test"); 6289#endif 6290 (void) puts("c = color test pattern"); 6291#if USE_WIDEC_SUPPORT 6292 (void) puts("C = color test pattern using wide-character calls"); 6293#endif 6294 if (top) 6295 (void) puts("d = edit RGB color values"); 6296#if USE_SOFTKEYS 6297 (void) puts("e = exercise soft keys"); 6298#if USE_WIDEC_SUPPORT 6299 (void) puts("E = exercise soft keys using wide-characters"); 6300#endif 6301#endif 6302 (void) puts("f = display ACS characters"); 6303#if USE_WIDEC_SUPPORT 6304 (void) puts("F = display Wide-ACS characters"); 6305#endif 6306 (void) puts("g = display windows and scrolling"); 6307 (void) puts("i = test of flushinp()"); 6308 (void) puts("k = display character attributes"); 6309#if USE_LIBMENU 6310 (void) puts("m = menu code test"); 6311#endif 6312#if USE_LIBPANEL 6313 (void) puts("o = exercise panels library"); 6314#if USE_WIDEC_SUPPORT 6315 (void) puts("O = exercise panels with wide-characters"); 6316#endif 6317#endif 6318 (void) puts("p = exercise pad features"); 6319 (void) puts("q = quit"); 6320#if USE_LIBFORM 6321 (void) puts("r = exercise forms code"); 6322#endif 6323 (void) puts("s = overlapping-refresh test"); 6324#if USE_LIBMENU && defined(TRACE) 6325 (void) puts("t = set trace level"); 6326#endif 6327 (void) puts("? = repeat this command summary"); 6328 6329 (void) fputs("> ", stdout); 6330 (void) fflush(stdout); /* necessary under SVr4 curses */ 6331 6332 /* 6333 * This used to be an 'fgets()' call. However (on Linux, at least) 6334 * mixing stream I/O and 'read()' (used in the library) causes the 6335 * input stream to be flushed when switching between the two. 6336 */ 6337 command = 0; 6338 for (;;) { 6339 char ch = '\0'; 6340 if (read(fileno(stdin), &ch, 1) <= 0) { 6341 if (command == 0) 6342 command = 'q'; 6343 break; 6344 } else if (command == 0 && !isspace(UChar(ch))) { 6345 command = ch; 6346 } else if (ch == '\n' || ch == '\r') { 6347 if ((command == 'd') && !top) { 6348 (void) fputs("Do not nest test-d\n", stdout); 6349 command = 0; 6350 } 6351 if (command != 0) 6352 break; 6353 (void) fputs("> ", stdout); 6354 (void) fflush(stdout); 6355 } 6356 } 6357 6358 if (do_single_test(command)) { 6359 /* 6360 * This may be overkill; it's intended to reset everything back 6361 * to the initial terminal modes so that tests don't get in 6362 * each other's way. 6363 */ 6364 flushinp(); 6365 set_terminal_modes(); 6366 reset_prog_mode(); 6367 clear(); 6368 refresh(); 6369 endwin(); 6370 if (command == '?') { 6371 (void) puts("This is the ncurses capability tester."); 6372 (void) 6373 puts("You may select a test from the main menu by typing the"); 6374 (void) 6375 puts("key letter of the choice (the letter to left of the =)"); 6376 (void) 6377 puts("at the > prompt. Type `q' to exit."); 6378 } 6379 continue; 6380 } 6381 } while 6382 (command != 'q'); 6383} 6384 6385/*+------------------------------------------------------------------------- 6386 main(argc,argv) 6387--------------------------------------------------------------------------*/ 6388 6389#define okCOLOR(n) ((n) >= 0 && (n) < max_colors) 6390#define okRGB(n) ((n) >= 0 && (n) <= 1000) 6391 6392int 6393main(int argc, char *argv[]) 6394{ 6395 int c; 6396 int my_e_param = 1; 6397#ifdef NCURSES_VERSION 6398 int default_fg = COLOR_WHITE; 6399 int default_bg = COLOR_BLACK; 6400 bool assumed_colors = FALSE; 6401 bool default_colors = FALSE; 6402#endif 6403 char *palette_file = 0; 6404 bool monochrome = FALSE; 6405 6406 setlocale(LC_ALL, ""); 6407 6408 while ((c = getopt(argc, argv, "a:de:fhmp:s:t:")) != -1) { 6409 switch (c) { 6410#ifdef NCURSES_VERSION 6411 case 'a': 6412 assumed_colors = TRUE; 6413 sscanf(optarg, "%d,%d", &default_fg, &default_bg); 6414 break; 6415 case 'd': 6416 default_colors = TRUE; 6417 break; 6418#endif 6419 case 'e': 6420 my_e_param = atoi(optarg); 6421#ifdef NCURSES_VERSION 6422 if (my_e_param > 3) /* allow extended layouts */ 6423 usage(); 6424#else 6425 if (my_e_param > 1) 6426 usage(); 6427#endif 6428 break; 6429#if HAVE_RIPOFFLINE 6430 case 'f': 6431 ripoffline(-1, rip_footer); 6432 break; 6433 case 'h': 6434 ripoffline(1, rip_header); 6435 break; 6436#endif /* HAVE_RIPOFFLINE */ 6437 case 'm': 6438 monochrome = TRUE; 6439 break; 6440 case 'p': 6441 palette_file = optarg; 6442 break; 6443#if USE_LIBPANEL 6444 case 's': 6445 nap_msec = atol(optarg); 6446 break; 6447#endif 6448#ifdef TRACE 6449 case 't': 6450 save_trace = (unsigned) strtol(optarg, 0, 0); 6451 break; 6452#endif 6453 default: 6454 usage(); 6455 } 6456 } 6457 6458 /* 6459 * If there's no menus (unlikely for ncurses!), then we'll have to set 6460 * tracing on initially, just in case the user wants to test something that 6461 * doesn't involve wGetchar. 6462 */ 6463#ifdef TRACE 6464 /* enable debugging */ 6465#if !USE_LIBMENU 6466 trace(save_trace); 6467#else 6468 if (!isatty(fileno(stdin))) 6469 trace(save_trace); 6470#endif /* USE_LIBMENU */ 6471#endif /* TRACE */ 6472 6473#if USE_SOFTKEYS 6474 /* tell it we're going to play with soft keys */ 6475 slk_init(my_e_param); 6476#endif 6477 6478#ifdef SIGUSR1 6479 /* set up null signal catcher so we can see what interrupts to getch do */ 6480 signal(SIGUSR1, announce_sig); 6481#endif 6482 6483 /* we must initialize the curses data structure only once */ 6484 initscr(); 6485 bkgdset(BLANK); 6486 6487 /* tests, in general, will want these modes */ 6488 use_colors = monochrome ? FALSE : has_colors(); 6489 6490 if (use_colors) { 6491 start_color(); 6492#ifdef NCURSES_VERSION_PATCH 6493 max_colors = COLORS; /* was > 16 ? 16 : COLORS */ 6494#if HAVE_USE_DEFAULT_COLORS 6495 if (default_colors) { 6496 use_default_colors(); 6497 min_colors = -1; 6498 } 6499#if NCURSES_VERSION_PATCH >= 20000708 6500 else if (assumed_colors) 6501 assume_default_colors(default_fg, default_bg); 6502#endif 6503#endif 6504#else /* normal SVr4 curses */ 6505 max_colors = COLORS; /* was > 8 ? 8 : COLORS */ 6506#endif 6507 max_pairs = COLOR_PAIRS; /* was > 256 ? 256 : COLOR_PAIRS */ 6508 6509 if (can_change_color()) { 6510 short cp; 6511 all_colors = typeMalloc(RGB_DATA, (unsigned) max_colors); 6512 for (cp = 0; cp < max_colors; ++cp) { 6513 color_content(cp, 6514 &all_colors[cp].red, 6515 &all_colors[cp].green, 6516 &all_colors[cp].blue); 6517 } 6518 if (palette_file != 0) { 6519 FILE *fp = fopen(palette_file, "r"); 6520 if (fp != 0) { 6521 char buffer[BUFSIZ]; 6522 int red, green, blue; 6523 int scale = 1000; 6524 while (fgets(buffer, sizeof(buffer), fp) != 0) { 6525 if (sscanf(buffer, "scale:%d", &c) == 1) { 6526 scale = c; 6527 } else if (sscanf(buffer, "%d:%d %d %d", 6528 &c, 6529 &red, 6530 &green, 6531 &blue) == 4 6532 && okCOLOR(c) 6533 && okRGB(red) 6534 && okRGB(green) 6535 && okRGB(blue)) { 6536 all_colors[c].red = (short) ((red * 1000) / scale); 6537 all_colors[c].green = (short) ((green * 1000) / scale); 6538 all_colors[c].blue = (short) ((blue * 1000) / scale); 6539 } 6540 } 6541 fclose(fp); 6542 } 6543 } 6544 } 6545 } 6546 set_terminal_modes(); 6547 def_prog_mode(); 6548 6549 /* 6550 * Return to terminal mode, so we're guaranteed of being able to 6551 * select terminal commands even if the capabilities are wrong. 6552 */ 6553 endwin(); 6554 6555#if HAVE_CURSES_VERSION 6556 (void) printf("Welcome to %s. Press ? for help.\n", curses_version()); 6557#elif defined(NCURSES_VERSION_MAJOR) && defined(NCURSES_VERSION_MINOR) && defined(NCURSES_VERSION_PATCH) 6558 (void) printf("Welcome to ncurses %d.%d.%d. Press ? for help.\n", 6559 NCURSES_VERSION_MAJOR, 6560 NCURSES_VERSION_MINOR, 6561 NCURSES_VERSION_PATCH); 6562#else 6563 (void) puts("Welcome to ncurses. Press ? for help."); 6564#endif 6565 6566 main_menu(TRUE); 6567 6568 ExitProgram(EXIT_SUCCESS); 6569} 6570 6571/* ncurses.c ends here */ 6572