• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  * Copyright 2018-2021,2022 Thomas E. Dickey                                *
3  * Copyright 2017 Free Software Foundation, Inc.                            *
4  *                                                                          *
5  * Permission is hereby granted, free of charge, to any person obtaining a  *
6  * copy of this software and associated documentation files (the            *
7  * "Software"), to deal in the Software without restriction, including      *
8  * without limitation the rights to use, copy, modify, merge, publish,      *
9  * distribute, distribute with modifications, sublicense, and/or sell       *
10  * copies of the Software, and to permit persons to whom the Software is    *
11  * furnished to do so, subject to the following conditions:                 *
12  *                                                                          *
13  * The above copyright notice and this permission notice shall be included  *
14  * in all copies or substantial portions of the Software.                   *
15  *                                                                          *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
19  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
20  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
21  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
22  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
23  *                                                                          *
24  * Except as contained in this notice, the name(s) of the above copyright   *
25  * holders shall not be used in advertising or otherwise to promote the     *
26  * sale, use or other dealings in this Software without prior written       *
27  * authorization.                                                           *
28  ****************************************************************************/
29 /*
30  * $Id: demo_new_pair.c,v 1.27 2022/12/04 00:40:11 tom Exp $
31  *
32  * Demonstrate the alloc_pair() function.
33  */
34 
35 #include <test.priv.h>
36 #include <time.h>
37 #include <popup_msg.h>
38 
39 #if HAVE_ALLOC_PAIR && USE_WIDEC_SUPPORT
40 
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 
45 #define MAX_BITS 8		/* all but A_ALTCHARSET */
46 #define MAX_ATTR ((1<<MAX_BITS)-1)
47 
48 static bool
valid_cap(NCURSES_CONST char * name)49 valid_cap(NCURSES_CONST char *name)
50 {
51     char *value = tigetstr(name);
52     return (value != 0 && value != (char *) -1) ? TRUE : FALSE;
53 }
54 
55 static attr_t
next_attr(int now)56 next_attr(int now)
57 {
58     static bool init = FALSE;
59     static attr_t table[MAX_BITS * MAX_BITS];
60     static int limit = 0;
61 
62     if (!init) {
63 	int j, k;
64 	attr_t bits[MAX_BITS];
65 
66 	init = TRUE;
67 	bits[limit++] = WA_NORMAL;
68 	if (valid_cap("smso"))
69 	    bits[limit++] = WA_STANDOUT;
70 	if (valid_cap("smul"))
71 	    bits[limit++] = WA_UNDERLINE;
72 	if (valid_cap("rev"))
73 	    bits[limit++] = WA_REVERSE;
74 	if (valid_cap("blink"))
75 	    bits[limit++] = WA_BLINK;
76 	if (valid_cap("dim"))
77 	    bits[limit++] = WA_DIM;
78 	if (valid_cap("bold"))
79 	    bits[limit++] = WA_BOLD;
80 	for (j = 0; j < limit; ++j) {
81 	    for (k = 0; k < limit; ++k) {
82 		table[j * limit + k] = bits[j] | bits[k];
83 	    }
84 	}
85     }
86     return table[now % limit];
87 }
88 
89 static void
our_content(int pair,int * fg,int * bg)90 our_content(int pair, int *fg, int *bg)
91 {
92     pair %= COLOR_PAIRS;
93     *fg = (pair / COLORS) % COLORS;
94     *bg = (pair % COLORS);
95 }
96 
97 static int
make_color(int now)98 make_color(int now)
99 {
100     int fg, bg;
101     our_content(now, &fg, &bg);
102     return alloc_pair(fg, bg);
103 }
104 
105 static int
next_color(int now)106 next_color(int now)
107 {
108     int result = 0;
109     if ((short) now > 0) {
110 	if (now < COLOR_PAIRS) {
111 	    int fg, bg;
112 	    our_content(now, &fg, &bg);
113 	    if (init_pair((short) now, (short) fg, (short) bg) != OK)
114 		now = ERR;
115 	} else {
116 	    now %= COLOR_PAIRS;
117 	}
118 	result = now;
119     }
120     return result;
121 }
122 
123 static time_t
now(void)124 now(void)
125 {
126     return time((time_t *) 0);
127 }
128 
129 static void
usage(int ok)130 usage(int ok)
131 {
132     static const char *msg[] =
133     {
134 	"Usage: demo_new_pair [options]"
135 	,""
136 	,"Repeatedly print using all possible color combinations."
137 	,""
138 	,USAGE_COMMON
139 	,"Options:"
140 	," -g       use getcchar to check setcchar"
141 	," -i       use init_pair rather than alloc_pair"
142 	," -p       start in paged-mode"
143 	," -s       start in single-step mode"
144 	," -w       print a wide-character cell"
145     };
146     unsigned n;
147     for (n = 0; n < SIZEOF(msg); ++n) {
148 	fprintf(stderr, "%s\n", msg[n]);
149     }
150     ExitProgram(ok ? EXIT_SUCCESS : EXIT_FAILURE);
151 }
152 
153 #define use_pages() \
154 	paged_mode = TRUE, single_mode = TRUE
155 
156 #define use_single() \
157 	paged_mode = FALSE, single_mode = TRUE
158 
159 #define update_modes() \
160 	    scrollok(stdscr, !paged_mode); \
161 	    nodelay(stdscr, !single_mode || paged_mode)
162 /* *INDENT-OFF* */
VERSION_COMMON()163 VERSION_COMMON()
164 /* *INDENT-ON* */
165 
166 int
167 main(int argc, char *argv[])
168 {
169     static const char *help[] =
170     {
171 	"This program iterates over the possible color combinations,",
172 	"allocating or initializing color pairs.  For best results,",
173 	"choose screen-width dividing evenly into the number of colors,",
174 	"e.g.,",
175 	"",
176 	"  32x64,32x128  256 colors",
177 	"  24x44,24x88   88 colors",
178 	"  32x64,24x128  16 colors",
179 	"",
180 	"Keys:",
181 	"  c      toggle between coloring and de-coloring cells",
182 	"  p      show one page at a time",
183 	"  s      show one character at a time",
184 	" <space> display char/page without pausing",
185 	"  v/V    cycle through video attributes",
186 	"  w      toggle between \"#\" and a double-width equivalent",
187 	"  ?      print this screen (exit on any character).",
188 	"",
189 	"To exit this program, press ^Q, ^[ or \"q\".",
190 	0
191     };
192 
193     bool done = FALSE;
194     bool check_set = FALSE;
195     bool clobber = FALSE;
196     bool hascolor = FALSE;
197     bool use_init = FALSE;
198     bool use_wide = FALSE;
199     bool paged_mode = FALSE;
200     bool single_mode = FALSE;
201     int video_mode = 0;
202     int current;
203     int ch;
204     wchar_t wch[2];
205     time_t start = now();
206     long total_cells = 0;
207     FILE *output = 0;
208 
209     setlocale(LC_ALL, "");
210 
211     while ((ch = getopt(argc, argv, OPTS_COMMON "gipsw")) != -1) {
212 	switch (ch) {
213 	case 'g':
214 	    check_set = TRUE;
215 	    break;
216 	case 'i':
217 	    use_init = TRUE;
218 	    break;
219 	case 'p':
220 	    use_pages();
221 	    break;
222 	case 's':
223 	    use_single();
224 	    break;
225 	case 'w':
226 	    use_wide = TRUE;
227 	    break;
228 	case OPTS_VERSION:
229 	    show_version(argv);
230 	    ExitProgram(EXIT_SUCCESS);
231 	default:
232 	    usage(ch == OPTS_USAGE);
233 	    /* NOTREACHED */
234 	}
235     }
236 
237     if (isatty(fileno(stderr))) {
238 	output = stderr;
239     } else if ((ch = open("/dev/tty", O_WRONLY)) >= 0) {
240 	output = fdopen(ch, "w");
241     } else {
242 	fprintf(stderr, "cannot open terminal for output\n");
243 	ExitProgram(EXIT_FAILURE);
244     }
245     if (newterm(NULL, output, stdin) == 0) {
246 	fprintf(stderr, "Cannot initialize terminal\n");
247 	fclose(output);
248 	ExitProgram(EXIT_FAILURE);
249     }
250     (void) cbreak();		/* read chars without wait for \n */
251     (void) noecho();		/* don't echo input */
252     update_modes();
253     curs_set(0);
254 
255     keypad(stdscr, TRUE);
256 
257     if ((hascolor = has_colors())) {
258 	start_color();
259 	current = 1;
260     } else {
261 	current = 0;
262     }
263 
264     /*
265      * Repeatedly cycle through all colors, initializing pairs as needed.
266      * Provide for single-stepping, or page-at-a-time, as well as quitting.
267      */
268     while (!done) {
269 	cchar_t temp;
270 	attr_t my_attrs;
271 	int my_pair;
272 
273 	switch (getch()) {
274 	case HELP_KEY_1:
275 	    popup_msg(stdscr, help);
276 	    break;
277 	case 'p':
278 	    /* step-by-page */
279 	    use_pages();
280 	    update_modes();
281 	    break;
282 	case 's':
283 	    /* step-by-char */
284 	    use_single();
285 	    update_modes();
286 	    break;
287 	case ' ':
288 	    single_mode = FALSE;
289 	    update_modes();
290 	    break;
291 	case QUIT:
292 	case ESCAPE:
293 	case 'q':
294 	    done = TRUE;
295 	    continue;
296 	case 'c':
297 	    clobber = !clobber;
298 	    continue;
299 	case 'v':
300 	    if (--video_mode < 0)
301 		video_mode = MAX_ATTR;
302 	    continue;
303 	case 'V':
304 	    if (video_mode > MAX_ATTR)
305 		video_mode = 0;
306 	    continue;
307 	case 'w':
308 	    use_wide = !use_wide;
309 	    continue;
310 	case ERR:
311 	    break;
312 	default:
313 	    beep();
314 	    break;
315 	}
316 	if (hascolor) {
317 	    my_attrs = next_attr(video_mode);
318 	    if (clobber) {
319 		int fg, bg;
320 		our_content(current, &fg, &bg);
321 		my_pair = find_pair(fg, bg);
322 		if (my_pair > 0) {
323 		    free_pair(my_pair);
324 		}
325 		my_pair = 0;
326 	    } else {
327 		my_pair = (use_init
328 			   ? next_color(current)
329 			   : make_color(current));
330 	    }
331 	} else {
332 	    my_attrs = next_attr(current);
333 	    my_pair = 0;
334 	}
335 	if (my_pair < 0)
336 	    break;
337 	wch[0] = use_wide ? 0xff03 : '#';
338 	wch[1] = 0;
339 	setcchar(&temp, wch, my_attrs,
340 		 (short) my_pair,
341 		 (use_init ? NULL : (void *) &my_pair));
342 
343 	if (check_set) {
344 	    int problem = 0;
345 	    wchar_t chk_wch[2];
346 	    attr_t chk_attrs = 0;
347 	    short chk_pair = 0;
348 	    int chk_pair2 = 0;
349 
350 #define AllButColor(a) ((a) & (A_ATTRIBUTES & ~A_COLOR))
351 
352 	    if (getcchar(&temp, NULL, &chk_attrs, &chk_pair,
353 			 (use_init ? NULL : (void *) &chk_pair2)) != 2) {
354 		problem = 1;
355 	    } else if (getcchar(&temp, chk_wch, &chk_attrs, &chk_pair,
356 				(use_init ? NULL : (void *) &chk_pair2)) != OK) {
357 		problem = 2;
358 	    } else if (chk_wch[0] != wch[0]) {
359 		problem = 3;
360 	    } else if (AllButColor(my_attrs) != AllButColor(chk_attrs)) {
361 		problem = 4;
362 	    } else if (my_pair != chk_pair) {
363 		problem = 4;
364 	    } else if (!use_init && (my_pair != chk_pair2)) {
365 		problem = 5;
366 	    }
367 	    if (problem) {
368 		wch[0] = (wchar_t) (problem + '0');
369 		setcchar(&temp, wch, my_attrs,
370 			 (short) my_pair,
371 			 (use_init ? NULL : (void *) &my_pair));
372 	    }
373 	}
374 
375 	/*
376 	 * At the end of a page, move the cursor to the home position.
377 	 */
378 	if ((add_wch(&temp) == ERR) && paged_mode) {
379 	    nodelay(stdscr, !single_mode);
380 	    move(0, 0);
381 	}
382 	total_cells += 1 + (use_wide ? 1 : 0);
383 	++current;
384     }
385     stop_curses();
386     fclose(output);
387 
388     printf("%.1f cells/second\n",
389 	   (double) (total_cells) / (double) (now() - start));
390 
391     ExitProgram(EXIT_SUCCESS);
392 }
393 
394 #else
395 int
main(void)396 main(void)
397 {
398     printf("This program requires the ncurses alloc_pair function\n");
399     ExitProgram(EXIT_FAILURE);
400 }
401 #endif
402