1 /* $NetBSD: slk.c,v 1.21 2022/12/20 04:57:01 blymn Exp $ */ 2 3 /*- 4 * Copyright (c) 2017 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Roy Marples. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #include <limits.h> 34 #ifndef lint 35 __RCSID("$NetBSD: slk.c,v 1.21 2022/12/20 04:57:01 blymn Exp $"); 36 #endif /* not lint */ 37 38 #include <limits.h> 39 #include <ctype.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #ifdef HAVE_WCHAR 43 #include <wctype.h> 44 #endif 45 46 #include "curses.h" 47 #include "curses_private.h" 48 49 /* Terminals with real soft labels have NOT been tested. 50 * If you have such a device, please let us know so this comment 51 * can be adjusted. */ 52 53 /* POSIX says that each label can be up to 8 columns. 54 * However, our implementation can allow labels to expand beyond that. */ 55 //#define SLK_SIZE_DYNAMIC 56 #ifdef SLK_SIZE_DYNAMIC 57 #define SLK_SIZE MAX_SLK_LABEL 58 #else 59 #define SLK_SIZE MAX_SLK_COLS 60 #endif 61 62 static int slk_fmt = SLK_FMT_INVAL; /* fmt of slk_init */ 63 64 /* Safe variants of public functions. */ 65 static int __slk_attroff(SCREEN *, const chtype); 66 static int __slk_attron(SCREEN *, const chtype); 67 static int __slk_attrset(SCREEN *, const chtype); 68 #ifdef HAVE_WCHAR 69 static int __slk_attr_off(SCREEN *, const attr_t, void *); 70 static int __slk_attr_on(SCREEN *, const attr_t, void *); 71 static int __slk_attr_set(SCREEN *, const attr_t, short, void *opt); 72 static int __slk_color(SCREEN *, short); 73 #endif 74 75 static int __slk_clear(SCREEN *); 76 static char *__slk_label(SCREEN *, int); 77 static int __slk_restore(SCREEN *); 78 static int __slk_set(SCREEN *, int, const char *, int); 79 static int __slk_touch(SCREEN *); 80 #ifdef HAVE_WCHAR 81 static int __slk_wset(SCREEN *, int, const wchar_t *, int); 82 #endif 83 84 /* Internal engine parts. */ 85 static int __slk_ripoffline(WINDOW *, int); 86 static int __slk_set_finalise(SCREEN *, int); 87 static int __slk_draw(SCREEN *, int); 88 static int __slk_redraw(SCREEN *); 89 90 /* 91 * slk_init -- 92 * Init Soft Label Keys. 93 */ 94 int 95 slk_init(int fmt) 96 { 97 98 switch(fmt) { 99 case SLK_FMT_3_2_3: 100 case SLK_FMT_4_4: 101 break; 102 default: 103 return ERR; 104 } 105 106 slk_fmt = fmt; 107 /* Even if the terminal supports soft label keys directly, 108 * we need to reserve a line. */ 109 return ripoffline(-1, __slk_ripoffline); 110 } 111 112 /* 113 * slk_attron -- 114 * Test and set attributes on ripped off slk window. 115 */ 116 int 117 slk_attron(const chtype attr) 118 { 119 120 return __slk_attron(_cursesi_screen, attr); 121 } 122 123 #ifdef HAVE_WCHAR 124 /* 125 * slk_attr_on -- 126 * Test and set wide attributes on ripped off slk window. 127 */ 128 int 129 slk_attr_on(const attr_t attr, void *opt) 130 { 131 132 return __slk_attr_on(_cursesi_screen, attr, opt); 133 } 134 #endif /* HAVE_WCHAR */ 135 136 /* 137 * slk_attroff -- 138 * Test and unset attributes on ripped off slk window. 139 */ 140 int 141 slk_attroff(const chtype attr) 142 { 143 144 return __slk_attroff(_cursesi_screen, attr); 145 } 146 147 #ifdef HAVE_WCHAR 148 /* 149 * slk_attr_off -- 150 * Test and unset wide attributes on ripped off slk window. 151 */ 152 int 153 slk_attr_off(const attr_t attr, void *opt) 154 { 155 156 return __slk_attr_off(_cursesi_screen, attr, opt); 157 } 158 #endif /* HAVE_WCHAR */ 159 160 /* 161 * slk_attrset -- 162 * Set attributes and color pair on ripped off slk window. 163 */ 164 int 165 slk_attrset(const chtype attr) 166 { 167 168 return __slk_attrset(_cursesi_screen, attr); 169 } 170 171 #ifdef HAVE_WCHAR 172 /* 173 * slk_attr_set -- 174 * Set wide attributes and color pair on ripped off slk window. 175 */ 176 int 177 slk_attr_set(const attr_t attr, short pair, void *opt) 178 { 179 180 return __slk_attr_set(_cursesi_screen, attr, pair, opt); 181 } 182 #endif /* HAVE_WCHAR */ 183 184 /* 185 * slk_clear -- 186 * Clear slk from the current screen. 187 */ 188 int 189 slk_clear(void) 190 { 191 192 return __slk_clear(_cursesi_screen); 193 } 194 195 #ifdef HAVE_WCHAR 196 /* 197 * slk_color -- 198 * Set color pair on ripped off slk window. 199 */ 200 int 201 slk_color(short pair) 202 { 203 204 return __slk_color(_cursesi_screen, pair); 205 } 206 #endif /* HAVE_WCHAR */ 207 208 /* 209 * slk_label -- 210 * Return a pointer to the saved label for key labnum. 211 */ 212 char * 213 slk_label(int labnum) 214 { 215 216 return __slk_label(_cursesi_screen, labnum); 217 } 218 219 /* 220 * slk_wnoutrefresh -- 221 * Add the contents of the ripped off slk window to the virtual window. 222 */ 223 int 224 slk_noutrefresh(void) 225 { 226 227 return __slk_noutrefresh(_cursesi_screen); 228 } 229 230 /* 231 * slk_refresh -- 232 * Force a refresh for the ripped off slk window. 233 */ 234 int 235 slk_refresh(void) 236 { 237 238 if (slk_noutrefresh() == ERR) 239 return ERR; 240 return doupdate(); 241 } 242 243 /* 244 * slk_restore -- 245 * Retore slk to the screen after a slk_clear. 246 */ 247 int 248 slk_restore(void) 249 { 250 251 return __slk_restore(_cursesi_screen); 252 } 253 254 /* 255 * slk_set -- 256 * Sets the text of the label specified by labnum 257 * and how it is displayed. 258 */ 259 int 260 slk_set(int labnum, const char *label, int justify) 261 { 262 263 return __slk_set(_cursesi_screen, labnum, label, justify); 264 } 265 266 /* 267 * slk_touch -- 268 * Sets the ripped off slk window as modified. 269 */ 270 int 271 slk_touch(void) 272 { 273 274 return __slk_touch(_cursesi_screen); 275 } 276 277 #ifdef HAVE_WCHAR 278 /* 279 * slk_wset -- 280 * Sets the wide text of the label specified by labnum 281 * and how it is displayed. 282 */ 283 int 284 slk_wset(int labnum, const wchar_t *label, int justify) 285 { 286 287 return __slk_wset(_cursesi_screen, labnum, label, justify); 288 } 289 #endif /* HAVE_WCHAR */ 290 291 /* 292 * __slk_attron -- 293 * Test and set attributes on ripped off slk window. 294 */ 295 static int 296 __slk_attron(SCREEN *screen, const chtype attr) 297 { 298 299 if (screen == NULL || screen->slk_window == NULL) 300 return ERR; 301 return wattron(screen->slk_window, attr); 302 } 303 304 #ifdef HAVE_WCHAR 305 /* 306 * __slk_attr_on -- 307 * Test and set wide attributes on ripped off slk window. 308 */ 309 static int 310 __slk_attr_on(SCREEN *screen, const attr_t attr, void *opt) 311 { 312 313 if (screen == NULL || screen->slk_window == NULL) 314 return ERR; 315 return wattr_on(screen->slk_window, attr, opt); 316 } 317 #endif /* HAVE_WCHAR */ 318 319 /* 320 * __slk_attroff -- 321 * Test and unset attributes on ripped off slk window. 322 */ 323 static int 324 __slk_attroff(SCREEN *screen, const chtype attr) 325 { 326 327 if (screen == NULL || screen->slk_window == NULL) 328 return ERR; 329 return wattroff(screen->slk_window, attr); 330 } 331 332 #ifdef HAVE_WCHAR 333 /* 334 * __slk_attr_off -- 335 * Test and unset wide attributes on ripped off slk window. 336 */ 337 static int 338 __slk_attr_off(SCREEN *screen, const attr_t attr, void *opt) 339 { 340 341 if (screen == NULL || screen->slk_window == NULL) 342 return ERR; 343 return wattr_off(screen->slk_window, attr, opt); 344 } 345 #endif /* HAVE_WCHAR */ 346 347 /* 348 * __slk_attrset -- 349 * Set attributes and color pair on ripped off slk window. 350 */ 351 static int 352 __slk_attrset(SCREEN *screen, const chtype attr) 353 { 354 355 if (screen == NULL || screen->slk_window == NULL) 356 return ERR; 357 return wattrset(screen->slk_window, attr); 358 } 359 360 #ifdef HAVE_WCHAR 361 /* 362 * __slk_attr_set -- 363 * Set wide attributes and color pair on ripped off slk window. 364 */ 365 static int 366 __slk_attr_set(SCREEN *screen, const attr_t attr, short pair, void *opt) 367 { 368 369 if (screen == NULL || screen->slk_window == NULL) 370 return ERR; 371 return wattr_set(screen->slk_window, attr, pair, opt); 372 } 373 #endif /* HAVE_WCHAR */ 374 375 /* 376 * __slk_clear -- 377 * Clear slk from the current screen. 378 */ 379 static int 380 __slk_clear(SCREEN *screen) 381 { 382 383 if (screen == NULL) 384 return ERR; 385 screen->slk_hidden = true; 386 if (screen->is_term_slk) { 387 if (t_label_off(screen->term) == NULL) 388 return ERR; 389 return ti_putp(screen->term, 390 ti_tiparm(screen->term, t_label_off(screen->term))); 391 } 392 if (screen->slk_window == NULL) 393 return ERR; 394 werase(screen->slk_window); 395 return wrefresh(screen->slk_window); 396 } 397 398 #ifdef HAVE_WCHAR 399 /* 400 * __slk_color -- 401 * Set color pair on ripped off slk window. 402 */ 403 static int 404 __slk_color(SCREEN *screen, short pair) 405 { 406 407 if (screen == NULL || screen->slk_window == NULL) 408 return ERR; 409 return wcolor_set(screen->slk_window, pair, NULL); 410 } 411 #endif /* HAVE_WCHAR */ 412 413 /* 414 * __slk_label -- 415 * Return a pointer to the saved label for key labnum. 416 */ 417 static char * 418 __slk_label(SCREEN *screen, int labnum) 419 { 420 421 if (screen == NULL || labnum < 1 || labnum > screen->slk_nlabels) 422 return NULL; 423 return screen->slk_labels[--labnum].text; 424 } 425 426 /* 427 * __slk_wnoutrefresh -- 428 * Add the contents of the ripped off slk window to the virtual window. 429 */ 430 int 431 __slk_noutrefresh(SCREEN *screen) 432 { 433 434 if (screen == NULL || screen->slk_window == NULL) 435 return ERR; 436 return wnoutrefresh(screen->slk_window); 437 } 438 439 /* 440 * __slk_restore -- 441 * Retore slk to the screen after a slk_clear. 442 */ 443 static int 444 __slk_restore(SCREEN *screen) 445 { 446 447 if (screen == NULL) 448 return ERR; 449 screen->slk_hidden = false; 450 if (screen->is_term_slk) { 451 if (t_label_on(screen->term) == NULL) 452 return ERR; 453 return ti_putp(screen->term, 454 ti_tiparm(screen->term, t_label_on(screen->term))); 455 } 456 if (screen->slk_window == NULL) 457 return ERR; 458 if (__slk_redraw(screen) == ERR) 459 return ERR; 460 return wrefresh(screen->slk_window); 461 } 462 463 /* 464 * __slk_set -- 465 * Sets the text of the label specified by labnum 466 * and how it is displayed. 467 */ 468 static int 469 __slk_set(SCREEN *screen, int labnum, const char *label, int justify) 470 { 471 struct __slk_label *l; 472 const char *end; 473 size_t len; 474 char *text; 475 #ifdef HAVE_WCHAR 476 wchar_t wc; 477 size_t wc_len; 478 #endif 479 480 /* Check args. */ 481 if (screen == NULL || labnum < 1 || labnum > screen->slk_nlabels) 482 return ERR; 483 switch(justify) { 484 case SLK_JUSTIFY_LEFT: 485 case SLK_JUSTIFY_CENTER: 486 case SLK_JUSTIFY_RIGHT: 487 break; 488 default: 489 return ERR; 490 } 491 if (label == NULL) 492 label = ""; 493 494 /* Skip leading whitespace. */ 495 while(isspace((unsigned char)*label)) 496 label++; 497 /* Grab end. */ 498 end = label; 499 500 #ifdef HAVE_WCHAR 501 size_t endlen = strlen(end); 502 while (*end != '\0') { 503 wc_len = mbrtowc(&wc, end, endlen, &screen->sp); 504 if ((ssize_t)wc_len < 0) 505 return ERR; 506 if (!iswprint((wint_t)wc)) 507 break; 508 end += wc_len; 509 endlen -= wc_len; 510 } 511 #else 512 while(isprint((unsigned char)*end)) 513 end++; 514 #endif 515 len = end - label; 516 517 /* Take a backup, in-case we can grow the label. */ 518 if ((text = strndup(label, len)) == NULL) 519 return ERR; 520 521 /* All checks out, assign. */ 522 l = &screen->slk_labels[--labnum]; /* internal zero based index */ 523 l->text = text; 524 l->justify = justify; 525 526 __slk_set_finalise(screen, labnum); 527 return OK; 528 } 529 530 /* 531 * __slk_touch -- 532 * Sets the ripped off slk window as modified. 533 */ 534 static int 535 __slk_touch(SCREEN *screen) 536 { 537 538 if (screen == NULL || screen->slk_window == NULL) 539 return ERR; 540 return touchwin(screen->slk_window); 541 } 542 543 544 #ifdef HAVE_WCHAR 545 /* 546 * __slk_wset -- 547 * Sets the wide text of the label specified by labnum 548 * and how it is displayed. 549 */ 550 static int 551 __slk_wset(SCREEN *screen, int labnum, const wchar_t *label, int justify) 552 { 553 const wchar_t *olabel; 554 size_t len; 555 char *str; 556 int result = ERR; 557 558 if (screen == NULL) 559 return ERR; 560 __CTRACE(__CTRACE_INPUT, "__slk_wset: entry\n"); 561 olabel = label; 562 if ((len = wcsrtombs(NULL, &olabel, 0, &screen->sp)) == -1) { 563 __CTRACE(__CTRACE_INPUT, 564 "__slk_wset: conversion failed on char 0x%hx\n", 565 (uint16_t)*olabel); 566 return ERR; 567 } 568 569 __CTRACE(__CTRACE_INPUT, "__slk_wset: wcsrtombs %zu\n", len); 570 len++; /* We need to store the NULL character. */ 571 if ((str = malloc(len)) == NULL) 572 return ERR; 573 olabel = label; 574 if (wcsrtombs(str, &olabel, len, &screen->sp) == -1) 575 goto out; 576 result = __slk_set(screen, labnum, str, justify); 577 out: 578 free(str); 579 __CTRACE(__CTRACE_INPUT, "__slk_wset: return %s\n", 580 result == OK ? "OK" : "ERR"); 581 return result; 582 } 583 #endif /* HAVE_WCHAR */ 584 585 586 /* 587 * __slk_init -- 588 * Allocate structures. 589 */ 590 int 591 __slk_init(SCREEN *screen) 592 { 593 594 __slk_free(screen); /* safety */ 595 596 screen->slk_format = slk_fmt; 597 if (slk_fmt == SLK_FMT_INVAL) 598 return OK; 599 slk_fmt = SLK_FMT_INVAL; 600 601 switch(screen->slk_format) { 602 case SLK_FMT_3_2_3: 603 case SLK_FMT_4_4: 604 screen->slk_nlabels = 8; 605 break; 606 default: /* impossible */ 607 return ERR; 608 } 609 610 screen->slk_labels = calloc(screen->slk_nlabels, 611 sizeof(*screen->slk_labels)); 612 if (screen->slk_labels == NULL) 613 return ERR; 614 615 screen->is_term_slk = 616 t_plab_norm(screen->term) != NULL && 617 t_num_labels(screen->term) > 0; 618 if (screen->is_term_slk) { 619 __unripoffline(__slk_ripoffline); 620 screen->slk_nlabels = t_num_labels(screen->term); 621 screen->slk_label_len = t_label_width(screen->term); 622 /* XXX label_height, label_format? */ 623 } 624 625 return OK; 626 } 627 628 /* 629 * __slk_free -- 630 * Free allocates resources. 631 */ 632 void 633 __slk_free(SCREEN *screen) 634 { 635 int i; 636 637 if (screen->slk_window != NULL) 638 delwin(screen->slk_window); 639 for (i = 0; i < screen->slk_nlabels; i++) 640 free(screen->slk_labels[i].text); 641 free(screen->slk_labels); 642 } 643 644 /* 645 * __slk_ripoffline -- 646 * ripoffline callback to accept a WINDOW to create our keys. 647 */ 648 static int 649 __slk_ripoffline(WINDOW *window, int cols) 650 { 651 652 if (window == NULL) 653 return ERR; 654 window->screen->slk_window = window; 655 wattron(window, 656 (t_no_color_video(window->screen->term) & 1) == 0 657 ? A_STANDOUT : A_REVERSE); 658 __slk_resize(window->screen, cols); 659 return OK; 660 } 661 662 /* 663 * __slk_resize -- 664 * Size and position the labels in the ripped off slk window. 665 */ 666 int 667 __slk_resize(SCREEN *screen, int cols) 668 { 669 int x = 0; 670 struct __slk_label *l; 671 672 if (screen == NULL) 673 return ERR; 674 if (screen->is_term_slk || screen->slk_nlabels == 0) 675 return OK; 676 677 screen->slk_label_len = (cols / screen->slk_nlabels) - 1; 678 if (screen->slk_label_len > SLK_SIZE) 679 screen->slk_label_len = SLK_SIZE; 680 681 l = screen->slk_labels; 682 683 switch(screen->slk_format) { 684 case SLK_FMT_3_2_3: 685 /* Left 3 */ 686 (l++)->x = x; 687 (l++)->x = (x += screen->slk_label_len + 1); 688 (l++)->x = (x += screen->slk_label_len + 1); 689 690 /* Middle 2 */ 691 x = cols / 2; 692 (l++)->x = x -(screen->slk_label_len + 1); 693 (l++)->x = x + 1; 694 695 /* Right 3 */ 696 x = (cols - ((screen->slk_label_len + 1) * 3)) + 1; 697 (l++)->x = x; 698 (l++)->x = (x += screen->slk_label_len + 1); 699 (l++)->x = (x += screen->slk_label_len + 1); 700 break; 701 702 case SLK_FMT_4_4: 703 { 704 int i, half; 705 706 half = screen->slk_nlabels / 2; 707 for (i = 0; i < screen->slk_nlabels; i++) { 708 (l++)->x = x; 709 x += screen->slk_label_len; 710 /* Split labels in half */ 711 if (i == half - 1) 712 x = cols - (screen->slk_label_len * half) + 1; 713 } 714 break; 715 } 716 } 717 718 /* Write text to the labels. */ 719 for (x = 0; x < screen->slk_nlabels; x++) 720 __slk_set_finalise(screen, x); 721 722 return __slk_redraw(screen); 723 } 724 725 /* 726 * __slk_set_finalise -- 727 * Does the grunt work of positioning and sizing the text in the label. 728 */ 729 static int 730 __slk_set_finalise(SCREEN *screen, int labnum) 731 { 732 struct __slk_label *l; 733 size_t spc, len, width, x; 734 char *p; 735 736 l = &screen->slk_labels[labnum]; 737 spc = screen->slk_label_len; 738 739 #ifdef HAVE_WCHAR 740 len = 0; 741 width = 0; 742 if (l->text != NULL) { 743 size_t plen; 744 745 p = l->text; 746 plen = strlen(l->text); 747 while (*p != '\0') { 748 size_t mblen; 749 wchar_t wc; 750 int w; 751 752 mblen = mbrtowc(&wc, p, plen, &screen->sp); 753 if ((ssize_t)mblen < 0) 754 return ERR; 755 w = wcwidth(wc); 756 if (width + w > spc) 757 break; 758 width += w; 759 len += mblen; 760 p += mblen; 761 plen -= mblen; 762 } 763 } 764 #else 765 len = l->text == NULL ? 0 : strlen(l->text); 766 if (len > spc) 767 len = spc; 768 width = len; 769 #endif 770 771 switch(l->justify) { 772 case SLK_JUSTIFY_LEFT: 773 x = 0; 774 break; 775 case SLK_JUSTIFY_CENTER: 776 x = (spc - width) / 2; 777 if (x + width > spc) 778 x--; 779 break; 780 case SLK_JUSTIFY_RIGHT: 781 x = spc - width; 782 break; 783 default: 784 return ERR; /* impossible */ 785 } 786 787 p = l->label; 788 if (x != 0) { 789 memset(p, ' ', x); 790 p += x; 791 spc -= x; 792 } 793 if (len != 0) { 794 memcpy(p, l->text, len); 795 p += len; 796 spc -= width; 797 } 798 if (spc != 0) { 799 memset(p, ' ', spc); 800 p += spc; 801 } 802 *p = '\0'; /* Terminate for plab_norm. */ 803 804 return __slk_draw(screen, labnum); 805 } 806 807 /* 808 * __slk_draw -- 809 * Draws the specified key. 810 */ 811 static int 812 __slk_draw(SCREEN *screen, int labnum) 813 { 814 const struct __slk_label *l; 815 int retval, inc, lcnt, tx; 816 char ts[MB_LEN_MAX]; 817 #ifdef HAVE_WCHAR 818 cchar_t cc; 819 wchar_t wc[2]; 820 #endif 821 822 __CTRACE(__CTRACE_INPUT, "__slk_draw: screen %p, label %d\n", screen, 823 labnum); 824 825 if (screen->slk_hidden) 826 return OK; 827 828 retval = OK; /* quiet gcc... */ 829 830 l = &screen->slk_labels[labnum]; 831 if (screen->is_term_slk) 832 return ti_putp(screen->term, 833 ti_tiparm(screen->term, 834 t_plab_norm(screen->term), labnum + 1, l->label)); 835 else if (screen->slk_window != NULL) { 836 if ((labnum != screen->slk_nlabels - 1) || 837 (screen->slk_window->flags & __SCROLLOK) || 838 ((l->x + screen->slk_label_len) < screen->slk_window->maxx)) { 839 retval = mvwaddnstr(screen->slk_window, 0, l->x, 840 l->label, strlen(l->label)); 841 } else { 842 lcnt = 0; 843 tx = 0; 844 while (lcnt < screen->slk_label_len) { 845 inc = wctomb(ts, l->label[lcnt]); 846 if (inc < 0) { 847 /* conversion failed, skip? */ 848 lcnt++; 849 continue; 850 } 851 852 __CTRACE(__CTRACE_INPUT, 853 "__slk_draw: last label, (%d,%d) char[%d] 0x%x\n", 854 l->x + tx, 0, lcnt, l->label[lcnt]); 855 __CTRACE(__CTRACE_INPUT, "__slk_draw: label len %d, wcwidth %d\n", 856 screen->slk_label_len, wcwidth(l->label[lcnt])); 857 #ifdef HAVE_WCHAR 858 wc[0] = l->label[lcnt]; 859 wc[1] = L'\0'; 860 if (setcchar(&cc, wc, 861 screen->slk_window->wattr, 0, 862 NULL) == ERR) 863 return ERR; 864 #endif 865 866 if (l->x + wcwidth(l->label[lcnt] + tx) >= 867 screen->slk_label_len) { 868 /* last character that will fit 869 * so insert it to avoid scroll 870 */ 871 #ifdef HAVE_WCHAR 872 retval = mvwins_wch(screen->slk_window, 873 0, l->x + tx, &cc); 874 #else 875 retval = mvwinsch(screen->slk_window, 876 0, l->x + tx, l->label[lcnt]); 877 #endif 878 } else { 879 #ifdef HAVE_WCHAR 880 retval = mvwadd_wch(screen->slk_window, 881 0, l->x + tx, &cc); 882 #else 883 retval = mvwaddch(screen->slk_window, 884 0, l->x + tx, l->label[lcnt]); 885 #endif 886 } 887 tx += wcwidth(l->label[lcnt]); 888 lcnt += inc; 889 } 890 } 891 892 return retval; 893 } else 894 return ERR; 895 } 896 897 /* 898 * __slk_draw -- 899 * Draws all the keys. 900 */ 901 static int 902 __slk_redraw(SCREEN *screen) 903 { 904 int i, result = OK; 905 906 for (i = 0; i < screen->slk_nlabels; i++) { 907 if (__slk_draw(screen, i) == ERR) 908 result = ERR; 909 } 910 return result; 911 } 912