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