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