Home | History | Annotate | Line # | Download | only in libcurses
slk.c revision 1.2.14.1
      1 /*	$NetBSD: slk.c,v 1.2.14.1 2018/10/20 06:58:22 pgoyette 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 #ifndef lint
     34 __RCSID("$NetBSD: slk.c,v 1.2.14.1 2018/10/20 06:58:22 pgoyette Exp $");
     35 #endif				/* not lint */
     36 
     37 #include <ctype.h>
     38 #include <stdlib.h>
     39 #include <string.h>
     40 #ifdef HAVE_WCHAR
     41 #include <wctype.h>
     42 #endif
     43 
     44 #include "curses.h"
     45 #include "curses_private.h"
     46 
     47 /* Terminals with real soft labels have NOT been tested.
     48  * If you have such a device, please let us know so this comment
     49  * can be adjusted. */
     50 
     51 /* POSIX says that each label can be up to 8 columns.
     52  * However, our implementation can allow labels to expand beyond that. */
     53 //#define	SLK_SIZE_DYNAMIC
     54 #ifdef SLK_SIZE_DYNAMIC
     55 #define	SLK_SIZE	MAX_SLK_LABEL
     56 #else
     57 #define	SLK_SIZE	MAX_SLK_COLS
     58 #endif
     59 
     60 static int	 slk_fmt = SLK_FMT_INVAL;	/* fmt of slk_init */
     61 
     62 /* Safe variants of public functions. */
     63 static int	 __slk_attron(SCREEN *, const chtype);
     64 static int	 __slk_attr_on(SCREEN *, const attr_t, void *);
     65 static int	 __slk_attroff(SCREEN *, const chtype);
     66 static int	 __slk_attr_off(SCREEN *, const attr_t, void *);
     67 static int	 __slk_attrset(SCREEN *, const chtype);
     68 static int	 __slk_attr_set(SCREEN *, const attr_t, short, void *opt);
     69 static int	 __slk_color(SCREEN *, short);
     70 static int	 __slk_clear(SCREEN *);
     71 static char	*__slk_label(SCREEN *, int);
     72 static int	 __slk_restore(SCREEN *);
     73 static int	 __slk_set(SCREEN *, int, const char *, int);
     74 static int	 __slk_touch(SCREEN *);
     75 static int	 __slk_wset(SCREEN *, int, const wchar_t *, int);
     76 
     77 /* Internal engine parts. */
     78 static int	 __slk_ripoffline(WINDOW *, int);
     79 static int	 __slk_set_finalise(SCREEN *, int);
     80 static int	 __slk_draw(SCREEN *, int);
     81 static int	 __slk_redraw(SCREEN *);
     82 
     83 /*
     84  * slk_init --
     85  *	Init Soft Label Keys.
     86  */
     87 int
     88 slk_init(int fmt)
     89 {
     90 
     91 	switch(fmt) {
     92 	case SLK_FMT_3_2_3:
     93 	case SLK_FMT_4_4:
     94 		break;
     95 	default:
     96 		return ERR;
     97 	}
     98 
     99 	slk_fmt = fmt;
    100 	/* Even if the terminal supports soft label keys directly,
    101 	 * we need to reserve a line. */
    102 	return ripoffline(-1, __slk_ripoffline);
    103 }
    104 
    105 /*
    106  * slk_attron --
    107  *	Test and set attributes on ripped off slk window.
    108  */
    109 int
    110 slk_attron(const chtype attr)
    111 {
    112 
    113 	return __slk_attron(_cursesi_screen, attr);
    114 }
    115 
    116 /*
    117  * slk_attr_on --
    118  *	Test and set wide attributes on ripped off slk window.
    119  */
    120 int
    121 slk_attr_on(const attr_t attr, void *opt)
    122 {
    123 
    124 	return __slk_attr_on(_cursesi_screen, attr, opt);
    125 }
    126 
    127 /*
    128  * slk_attroff --
    129  *	Test and unset attributes on ripped off slk window.
    130  */
    131 int
    132 slk_attroff(const chtype attr)
    133 {
    134 
    135 	return __slk_attroff(_cursesi_screen, attr);
    136 }
    137 
    138 /*
    139  * slk_attr_off --
    140  *	Test and unset wide attributes on ripped off slk window.
    141  */
    142 int
    143 slk_attr_off(const attr_t attr, void *opt)
    144 {
    145 
    146 	return __slk_attr_off(_cursesi_screen, attr, opt);
    147 }
    148 
    149 /*
    150  * slk_attrset --
    151  *	Set attributes and color pair on ripped off slk window.
    152  */
    153 int
    154 slk_attrset(const chtype attr)
    155 {
    156 
    157 	return __slk_attrset(_cursesi_screen, attr);
    158 }
    159 
    160 /*
    161  * slk_attr_set --
    162  *	Set wide attributes and color pair on ripped off slk window.
    163  */
    164 int
    165 slk_attr_set(const attr_t attr, short pair, void *opt)
    166 {
    167 
    168 	return __slk_attr_set(_cursesi_screen, attr, pair, opt);
    169 }
    170 
    171 /*
    172  * slk_clear --
    173  *	Clear slk from the current screen.
    174  */
    175 int
    176 slk_clear(void)
    177 {
    178 
    179 	return __slk_clear(_cursesi_screen);
    180 }
    181 
    182 /*
    183  * slk_color --
    184  *	Set color pair on ripped off slk window.
    185  */
    186 int
    187 slk_color(short pair)
    188 {
    189 
    190 	return __slk_color(_cursesi_screen, pair);
    191 }
    192 
    193 /*
    194  * slk_label --
    195  *	Return a pointer to the saved label for key labnum.
    196  */
    197 char *
    198 slk_label(int labnum)
    199 {
    200 
    201 	return __slk_label(_cursesi_screen, labnum);
    202 }
    203 
    204 /*
    205  * slk_wnoutrefresh --
    206  *	Add the contents of the ripped off slk window to the virtual window.
    207  */
    208 int
    209 slk_noutrefresh(void)
    210 {
    211 
    212 	return __slk_noutrefresh(_cursesi_screen);
    213 }
    214 
    215 /*
    216  * slk_refresh --
    217  *	Force a refresh for the ripped off slk window.
    218  */
    219 int
    220 slk_refresh(void)
    221 {
    222 
    223 	if (slk_noutrefresh() == ERR)
    224 		return ERR;
    225 	return doupdate();
    226 }
    227 
    228 /*
    229  * slk_restore --
    230  *	Retore slk to the screen after a slk_clear.
    231  */
    232 int
    233 slk_restore(void)
    234 {
    235 
    236 	return __slk_restore(_cursesi_screen);
    237 }
    238 
    239 /*
    240  * slk_set --
    241  *	Sets the text of the label specified by labnum
    242  *	and how it is displayed.
    243  */
    244 int
    245 slk_set(int labnum, const char *label, int justify)
    246 {
    247 
    248 	return __slk_set(_cursesi_screen, labnum, label, justify);
    249 }
    250 
    251 /*
    252  * slk_touch --
    253  *	Sets the ripped off slk window as modified.
    254  */
    255 int
    256 slk_touch(void)
    257 {
    258 
    259 	return __slk_touch(_cursesi_screen);
    260 }
    261 
    262 /*
    263  * slk_wset --
    264  *	Sets the wide text of the label specified by labnum
    265  *	and how it is displayed.
    266  */
    267 int
    268 slk_wset(int labnum, const wchar_t *label, int justify)
    269 {
    270 
    271 	return __slk_wset(_cursesi_screen, labnum, label, justify);
    272 }
    273 
    274 /*
    275  * __slk_attron --
    276  *	Test and set attributes on ripped off slk window.
    277  */
    278 static int
    279 __slk_attron(SCREEN *screen, const chtype attr)
    280 {
    281 
    282 	if (screen == NULL || screen->slk_window == NULL)
    283 		return ERR;
    284 	return wattron(screen->slk_window, attr);
    285 }
    286 
    287 /*
    288  * __slk_attr_on --
    289  *	Test and set wide attributes on ripped off slk window.
    290  */
    291 static int
    292 __slk_attr_on(SCREEN *screen, const attr_t attr, void *opt)
    293 {
    294 
    295 	if (screen == NULL || screen->slk_window == NULL)
    296 		return ERR;
    297 	return wattr_on(screen->slk_window, attr, opt);
    298 }
    299 
    300 /*
    301  * __slk_attroff --
    302  *	Test and unset attributes on ripped off slk window.
    303  */
    304 static int
    305 __slk_attroff(SCREEN *screen, const chtype attr)
    306 {
    307 
    308 	if (screen == NULL || screen->slk_window == NULL)
    309 		return ERR;
    310 	return wattroff(screen->slk_window, attr);
    311 }
    312 
    313 /*
    314  * __slk_attr_off --
    315  *	Test and unset wide attributes on ripped off slk window.
    316  */
    317 static int
    318 __slk_attr_off(SCREEN *screen, const attr_t attr, void *opt)
    319 {
    320 
    321 	if (screen == NULL || screen->slk_window == NULL)
    322 		return ERR;
    323 	return wattr_off(screen->slk_window, attr, opt);
    324 }
    325 
    326 /*
    327  * __slk_attrset --
    328  *	Set attributes and color pair on ripped off slk window.
    329  */
    330 static int
    331 __slk_attrset(SCREEN *screen, const chtype attr)
    332 {
    333 
    334 	if (screen == NULL || screen->slk_window == NULL)
    335 		return ERR;
    336 	return wattrset(screen->slk_window, attr);
    337 }
    338 
    339 /*
    340  * __slk_attr_set --
    341  *	Set wide attributes and color pair on ripped off slk window.
    342  */
    343 static int
    344 __slk_attr_set(SCREEN *screen, const attr_t attr, short pair, void *opt)
    345 {
    346 
    347 	if (screen == NULL || screen->slk_window == NULL)
    348 		return ERR;
    349 	return wattr_set(screen->slk_window, attr, pair, opt);
    350 }
    351 
    352 /*
    353  * __slk_clear --
    354  *	Clear slk from the current screen.
    355  */
    356 static int
    357 __slk_clear(SCREEN *screen)
    358 {
    359 
    360 	if (screen == NULL)
    361 		return ERR;
    362 	screen->slk_hidden = true;
    363 	if (screen->is_term_slk) {
    364 		if (t_label_off(screen->term) == NULL)
    365 			return ERR;
    366 		return ti_putp(screen->term,
    367 		    ti_tiparm(screen->term, t_label_off(screen->term)));
    368 	}
    369 	if (screen->slk_window == NULL)
    370 		return ERR;
    371 	werase(screen->slk_window);
    372 	return wrefresh(screen->slk_window);
    373 }
    374 
    375 /*
    376  * __slk_color --
    377  *	Set color pair on ripped off slk window.
    378  */
    379 static int
    380 __slk_color(SCREEN *screen, short pair)
    381 {
    382 
    383 	if (screen == NULL || screen->slk_window == NULL)
    384 		return ERR;
    385 	return wcolor_set(screen->slk_window, pair, NULL);
    386 }
    387 
    388 
    389 /*
    390  * __slk_label --
    391  *	Return a pointer to the saved label for key labnum.
    392  */
    393 static char *
    394 __slk_label(SCREEN *screen, int labnum)
    395 {
    396 
    397 	if (screen == NULL || labnum < 1 || labnum > screen->slk_nlabels)
    398 		return NULL;
    399 	return screen->slk_labels[--labnum].text;
    400 }
    401 
    402 /*
    403  * __slk_wnoutrefresh --
    404  *	Add the contents of the ripped off slk window to the virtual window.
    405  */
    406 int
    407 __slk_noutrefresh(SCREEN *screen)
    408 {
    409 
    410 	if (screen == NULL || screen->slk_window == NULL)
    411 		return ERR;
    412 	return wnoutrefresh(screen->slk_window);
    413 }
    414 
    415 /*
    416  * __slk_restore --
    417  *	Retore slk to the screen after a slk_clear.
    418  */
    419 static int
    420 __slk_restore(SCREEN *screen)
    421 {
    422 
    423 	if (screen == NULL)
    424 		return ERR;
    425 	screen->slk_hidden = false;
    426 	if (screen->is_term_slk) {
    427 		if (t_label_on(screen->term) == NULL)
    428 			return ERR;
    429 		return ti_putp(screen->term,
    430 		    ti_tiparm(screen->term, t_label_on(screen->term)));
    431 	}
    432 	if (screen->slk_window == NULL)
    433 		return ERR;
    434 	if (__slk_redraw(screen) == ERR)
    435 		return ERR;
    436 	return wrefresh(screen->slk_window);
    437 }
    438 
    439 /*
    440  * __slk_set --
    441  *	Sets the text of the label specified by labnum
    442  *	and how it is displayed.
    443  */
    444 static int
    445 __slk_set(SCREEN *screen, int labnum, const char *label, int justify)
    446 {
    447 	struct __slk_label *l;
    448 	const char *end;
    449 	size_t len;
    450 	char *text;
    451 #ifdef HAVE_WCHAR
    452 	wchar_t wc;
    453 	size_t wc_len;
    454 #endif
    455 
    456 	/* Check args. */
    457 	if (screen == NULL || labnum < 1 || labnum > screen->slk_nlabels)
    458 		return ERR;
    459 	switch(justify) {
    460 	case SLK_JUSTIFY_LEFT:
    461 	case SLK_JUSTIFY_CENTER:
    462 	case SLK_JUSTIFY_RIGHT:
    463 		break;
    464 	default:
    465 		return ERR;
    466 	}
    467 	if (label == NULL)
    468 		label = "";
    469 
    470 	/* Skip leading whitespace. */
    471 	while(isspace((unsigned char)*label))
    472 		label++;
    473 	/* Grab end. */
    474 	end = label;
    475 
    476 #ifdef HAVE_WCHAR
    477 	len = 0;
    478 	while (*end != '\0') {
    479 		if ((wc_len = mbrtowc(0, end, strlen(end), &screen->sp)) == -1)
    480 			return ERR;
    481 		mbrtowc(&wc, end, wc_len, &screen->sp);
    482 		if (!iswprint((wint_t)wc))
    483 			break;
    484 		len += wcwidth(wc);
    485 		end += wc_len;
    486 	}
    487 #else
    488 	while(isprint((unsigned char)*end))
    489 		end++;
    490 	len = end - label;
    491 #endif
    492 
    493 	/* Take a backup, in-case we can grow the label. */
    494 	if ((text = strndup(label, len)) == NULL)
    495 		return ERR;
    496 
    497 	/* All checks out, assign. */
    498 	l = &screen->slk_labels[--labnum]; /* internal zero based index */
    499 	l->text = text;
    500 	l->justify = justify;
    501 
    502 	__slk_set_finalise(screen, labnum);
    503 	return OK;
    504 }
    505 
    506 /*
    507  * __slk_touch --
    508  *	Sets the ripped off slk window as modified.
    509  */
    510 static int
    511 __slk_touch(SCREEN *screen)
    512 {
    513 
    514 	if (screen == NULL || screen->slk_window == NULL)
    515 		return ERR;
    516 	return touchwin(screen->slk_window);
    517 }
    518 
    519 /*
    520  * __slk_wset --
    521  *	Sets the wide text of the label specified by labnum
    522  *	and how it is displayed.
    523  */
    524 static int
    525 __slk_wset(SCREEN *screen, int labnum, const wchar_t *label, int justify)
    526 {
    527 #ifdef HAVE_WCHAR
    528 	const wchar_t *olabel;
    529 	size_t len;
    530 	char *str;
    531 	int result = ERR;
    532 
    533 	if (screen == NULL)
    534 		return ERR;
    535 	olabel = label;
    536 	if ((len = wcsrtombs(NULL, &olabel, 0, &screen->sp)) == -1)
    537 		return ERR;
    538 	len++; /* We need to store the NULL character. */
    539 	if ((str = malloc(len)) == NULL)
    540 		return ERR;
    541 	olabel = label;
    542 	if (wcsrtombs(str, &olabel, len, &screen->sp) == -1)
    543 		goto out;
    544 	result = __slk_set(screen, labnum, str, justify);
    545 out:
    546 	free(str);
    547 	return result;
    548 #else
    549 	return ERR;
    550 #endif
    551 }
    552 
    553 
    554 /*
    555  * __slk_init --
    556  *	Allocate structures.
    557  */
    558 int
    559 __slk_init(SCREEN *screen)
    560 {
    561 
    562 	__slk_free(screen);	/* safety */
    563 
    564 	screen->slk_format = slk_fmt;
    565 	if (slk_fmt == SLK_FMT_INVAL)
    566 		return OK;
    567 	slk_fmt = SLK_FMT_INVAL;
    568 
    569 	switch(screen->slk_format) {
    570 	case SLK_FMT_3_2_3:
    571 	case SLK_FMT_4_4:
    572 		screen->slk_nlabels = 8;
    573 		break;
    574 	default:	/* impossible */
    575 		return ERR;
    576 	}
    577 
    578 	screen->slk_labels = calloc(screen->slk_nlabels,
    579 				    sizeof(*screen->slk_labels));
    580 	if (screen->slk_labels == NULL)
    581 		return ERR;
    582 
    583 	screen->is_term_slk =
    584 	    t_plab_norm(screen->term) != NULL &&
    585 	    t_num_labels(screen->term) > 0;
    586 	if (screen->is_term_slk) {
    587 		__unripoffline(__slk_ripoffline);
    588 		screen->slk_nlabels = t_num_labels(screen->term);
    589 		screen->slk_label_len = t_label_width(screen->term);
    590 		/* XXX label_height, label_format? */
    591 	}
    592 
    593 	return OK;
    594 }
    595 
    596 /*
    597  * __slk_free --
    598  *	Free allocates resources.
    599  */
    600 void
    601 __slk_free(SCREEN *screen)
    602 {
    603 	int i;
    604 
    605 	if (screen->slk_window != NULL)
    606 		delwin(screen->slk_window);
    607 	for (i = 0; i < screen->slk_nlabels; i++)
    608 		free(screen->slk_labels[i].text);
    609 	free(screen->slk_labels);
    610 }
    611 
    612 /*
    613  * __slk_ripoffline --
    614  *	ripoffline callback to accept a WINDOW to create our keys.
    615  */
    616 static int
    617 __slk_ripoffline(WINDOW *window, int cols)
    618 {
    619 
    620 	if (window == NULL)
    621 		return ERR;
    622 	window->screen->slk_window = window;
    623 	wattron(window,
    624 	    (t_no_color_video(window->screen->term) & 1) == 0
    625 	    ? A_STANDOUT : A_REVERSE);
    626 	__slk_resize(window->screen, cols);
    627 	return OK;
    628 }
    629 
    630 /*
    631  * __slk_resize --
    632  *	Size and position the labels in the ripped off slk window.
    633  */
    634 int
    635 __slk_resize(SCREEN *screen, int cols)
    636 {
    637 	int x = 0;
    638 	struct __slk_label *l;
    639 
    640 	if (screen == NULL)
    641 		return ERR;
    642 	if (screen->is_term_slk || screen->slk_nlabels == 0)
    643 		return OK;
    644 
    645 	screen->slk_label_len = (cols / screen->slk_nlabels) - 1;
    646 	if (screen->slk_label_len > SLK_SIZE)
    647 		screen->slk_label_len = SLK_SIZE;
    648 
    649 	l = screen->slk_labels;
    650 
    651 	switch(screen->slk_format) {
    652 	case SLK_FMT_3_2_3:
    653 		/* Left 3 */
    654 		(l++)->x = x;
    655 		(l++)->x = (x += screen->slk_label_len + 1);
    656 		(l++)->x = (x += screen->slk_label_len + 1);
    657 
    658 		/* Middle 2 */
    659 		x = cols / 2;
    660 		(l++)->x = x -(screen->slk_label_len + 1);
    661 		(l++)->x = x + 1;
    662 
    663 		/* Right 3 */
    664 		x = (cols - ((screen->slk_label_len + 1) * 3)) + 1;
    665 		(l++)->x = x;
    666 		(l++)->x = (x += screen->slk_label_len + 1);
    667 		(l++)->x = (x += screen->slk_label_len + 1);
    668 		break;
    669 
    670 	case SLK_FMT_4_4:
    671 	{
    672 		int i, half;
    673 
    674 		half = screen->slk_nlabels / 2;
    675 		for (i = 0; i < screen->slk_nlabels; i++) {
    676 			(l++)->x = x;
    677 			x += screen->slk_label_len;
    678 			/* Split labels in half */
    679 			if (i == half - 1)
    680 				x = cols - (screen->slk_label_len * half) + 1;
    681 		}
    682 		break;
    683 	}
    684 	}
    685 
    686 	/* Write text to the labels. */
    687 	for (x = 0; x < screen->slk_nlabels; x++)
    688 		__slk_set_finalise(screen, x);
    689 
    690 	return __slk_redraw(screen);
    691 }
    692 
    693 /*
    694  * __slk_set_finalise --
    695  *	Does the grunt work of positioning and sizing the text in the label.
    696  */
    697 static int
    698 __slk_set_finalise(SCREEN *screen, int labnum)
    699 {
    700 	struct __slk_label *l;
    701 	size_t spc, len, x;
    702 	char *p;
    703 
    704 	l = &screen->slk_labels[labnum];
    705 	spc = screen->slk_label_len;
    706 
    707 #ifdef HAVE_WCHAR
    708 	len = 0;
    709 	if (l->text != NULL) {
    710 		wchar_t wc;
    711 
    712 		p = l->text;
    713 		while (*p != '\0') {
    714 			if ((x = mbrtowc(0, p, strlen(p), &screen->sp)) == -1)
    715 				return ERR;
    716 			mbrtowc(&wc, p, x, &screen->sp);
    717 			if (len + wcwidth(wc) > spc)
    718 				break;
    719 			len += wcwidth(wc);
    720 			p += x;
    721 		}
    722 	}
    723 #else
    724 	len = l->text == NULL ? 0 : strlen(l->text);
    725 	if (len > spc)
    726 		len = spc;
    727 #endif
    728 
    729 	switch(l->justify) {
    730 	case SLK_JUSTIFY_LEFT:
    731 		x = 0;
    732 		break;
    733 	case SLK_JUSTIFY_CENTER:
    734 		x = (spc - len) / 2;
    735 		if (x + len > spc)
    736 			x--;
    737 		break;
    738 	case SLK_JUSTIFY_RIGHT:
    739 		x = spc - len;
    740 		break;
    741 	default:
    742 		return ERR; /* impossible */
    743 	}
    744 
    745 	p = l->label;
    746 	if (x != 0) {
    747 		memset(p, ' ', x);
    748 		p += x;
    749 		spc -= x;
    750 	}
    751 	if (len != 0) {
    752 		memcpy(p, l->text, len);
    753 		p += len;
    754 		spc -= len;
    755 	}
    756 	if (spc != 0) {
    757 		memset(p, ' ', spc);
    758 		p += spc;
    759 	}
    760 	*p = '\0'; /* Terminate for plab_norm. */
    761 
    762 	return __slk_draw(screen, labnum);
    763 }
    764 
    765 /*
    766  * __slk_draw --
    767  *	Draws the specified key.
    768  */
    769 static int
    770 __slk_draw(SCREEN *screen, int labnum)
    771 {
    772 	const struct __slk_label *l;
    773 
    774 	if (screen->slk_hidden)
    775 		return OK;
    776 
    777 	l = &screen->slk_labels[labnum];
    778 	if (screen->is_term_slk)
    779 		return ti_putp(screen->term,
    780 		    ti_tiparm(screen->term,
    781 		    t_plab_norm(screen->term), labnum + 1, l->label));
    782 	else if (screen->slk_window != NULL)
    783 		return mvwaddnstr(screen->slk_window, 0, l->x,
    784 		    l->label, screen->slk_label_len);
    785 	else
    786 		return ERR;
    787 }
    788 
    789 /*
    790  * __slk_draw --
    791  *	Draws all the keys.
    792  */
    793 static int
    794 __slk_redraw(SCREEN *screen)
    795 {
    796 	int i, result = OK;
    797 
    798 	for (i = 0; i < screen->slk_nlabels; i++) {
    799 		if (__slk_draw(screen, i) == ERR)
    800 			result = ERR;
    801 	}
    802 	return result;
    803 }
    804