teken_demo.c revision 262861
1/*-
2 * Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: stable/10/sys/teken/demo/teken_demo.c 262861 2014-03-06 18:30:56Z jhb $
27 */
28
29#include <sys/ioctl.h>
30
31#include <assert.h>
32#include <errno.h>
33#include <inttypes.h>
34#include <locale.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <unistd.h>
38
39#include <ncurses.h>
40#if defined(__FreeBSD__)
41#include <libutil.h>
42#elif defined(__linux__)
43#include <pty.h>
44#else
45#include <util.h>
46#endif
47
48#include <teken.h>
49
50static tf_bell_t	test_bell;
51static tf_cursor_t	test_cursor;
52static tf_putchar_t	test_putchar;
53static tf_fill_t	test_fill;
54static tf_copy_t	test_copy;
55static tf_param_t	test_param;
56static tf_respond_t	test_respond;
57
58static teken_funcs_t tf = {
59	.tf_bell	= test_bell,
60	.tf_cursor	= test_cursor,
61	.tf_putchar	= test_putchar,
62	.tf_fill	= test_fill,
63	.tf_copy	= test_copy,
64	.tf_param	= test_param,
65	.tf_respond	= test_respond,
66};
67
68struct pixel {
69	teken_char_t	c;
70	teken_attr_t	a;
71};
72
73#define NCOLS	80
74#define NROWS	24
75struct pixel buffer[NCOLS][NROWS];
76
77static int ptfd;
78
79static void
80printchar(const teken_pos_t *p)
81{
82	int y, x, attr = 0;
83	struct pixel *px;
84	char str[5] = { 0 };
85
86	assert(p->tp_row < NROWS);
87	assert(p->tp_col < NCOLS);
88
89	px = &buffer[p->tp_col][p->tp_row];
90	/* No need to print right hand side of CJK character manually. */
91	if (px->a.ta_format & TF_CJK_RIGHT)
92		return;
93
94	/* Convert Unicode to UTF-8. */
95	if (px->c < 0x80) {
96		str[0] = px->c;
97	} else if (px->c < 0x800) {
98		str[0] = 0xc0 | (px->c >> 6);
99		str[1] = 0x80 | (px->c & 0x3f);
100	} else if (px->c < 0x10000) {
101		str[0] = 0xe0 | (px->c >> 12);
102		str[1] = 0x80 | ((px->c >> 6) & 0x3f);
103		str[2] = 0x80 | (px->c & 0x3f);
104	} else {
105		str[0] = 0xf0 | (px->c >> 18);
106		str[1] = 0x80 | ((px->c >> 12) & 0x3f);
107		str[2] = 0x80 | ((px->c >> 6) & 0x3f);
108		str[3] = 0x80 | (px->c & 0x3f);
109	}
110
111	if (px->a.ta_format & TF_BOLD)
112		attr |= A_BOLD;
113	if (px->a.ta_format & TF_UNDERLINE)
114		attr |= A_UNDERLINE;
115	if (px->a.ta_format & TF_BLINK)
116		attr |= A_BLINK;
117	if (px->a.ta_format & TF_REVERSE)
118		attr |= A_REVERSE;
119
120	bkgdset(attr | COLOR_PAIR(teken_256to8(px->a.ta_fgcolor) +
121	      8 * teken_256to8(px->a.ta_bgcolor)));
122	getyx(stdscr, y, x);
123	mvaddstr(p->tp_row, p->tp_col, str);
124	move(y, x);
125}
126
127static void
128test_bell(void *s __unused)
129{
130
131	beep();
132}
133
134static void
135test_cursor(void *s __unused, const teken_pos_t *p)
136{
137
138	move(p->tp_row, p->tp_col);
139}
140
141static void
142test_putchar(void *s __unused, const teken_pos_t *p, teken_char_t c,
143    const teken_attr_t *a)
144{
145
146	buffer[p->tp_col][p->tp_row].c = c;
147	buffer[p->tp_col][p->tp_row].a = *a;
148	printchar(p);
149}
150
151static void
152test_fill(void *s, const teken_rect_t *r, teken_char_t c,
153    const teken_attr_t *a)
154{
155	teken_pos_t p;
156
157	/* Braindead implementation of fill() - just call putchar(). */
158	for (p.tp_row = r->tr_begin.tp_row; p.tp_row < r->tr_end.tp_row; p.tp_row++)
159		for (p.tp_col = r->tr_begin.tp_col; p.tp_col < r->tr_end.tp_col; p.tp_col++)
160			test_putchar(s, &p, c, a);
161}
162
163static void
164test_copy(void *s __unused, const teken_rect_t *r, const teken_pos_t *p)
165{
166	int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */
167	teken_pos_t d;
168
169	/*
170	 * Copying is a little tricky. We must make sure we do it in
171	 * correct order, to make sure we don't overwrite our own data.
172	 */
173
174	nrow = r->tr_end.tp_row - r->tr_begin.tp_row;
175	ncol = r->tr_end.tp_col - r->tr_begin.tp_col;
176
177	if (p->tp_row < r->tr_begin.tp_row) {
178		/* Copy from top to bottom. */
179		if (p->tp_col < r->tr_begin.tp_col) {
180			/* Copy from left to right. */
181			for (y = 0; y < nrow; y++) {
182				d.tp_row = p->tp_row + y;
183				for (x = 0; x < ncol; x++) {
184					d.tp_col = p->tp_col + x;
185					buffer[d.tp_col][d.tp_row] =
186					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
187					printchar(&d);
188				}
189			}
190		} else {
191			/* Copy from right to left. */
192			for (y = 0; y < nrow; y++) {
193				d.tp_row = p->tp_row + y;
194				for (x = ncol - 1; x >= 0; x--) {
195					d.tp_col = p->tp_col + x;
196					buffer[d.tp_col][d.tp_row] =
197					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
198					printchar(&d);
199				}
200			}
201		}
202	} else {
203		/* Copy from bottom to top. */
204		if (p->tp_col < r->tr_begin.tp_col) {
205			/* Copy from left to right. */
206			for (y = nrow - 1; y >= 0; y--) {
207				d.tp_row = p->tp_row + y;
208				for (x = 0; x < ncol; x++) {
209					d.tp_col = p->tp_col + x;
210					buffer[d.tp_col][d.tp_row] =
211					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
212					printchar(&d);
213				}
214			}
215		} else {
216			/* Copy from right to left. */
217			for (y = nrow - 1; y >= 0; y--) {
218				d.tp_row = p->tp_row + y;
219				for (x = ncol - 1; x >= 0; x--) {
220					d.tp_col = p->tp_col + x;
221					buffer[d.tp_col][d.tp_row] =
222					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
223					printchar(&d);
224				}
225			}
226		}
227	}
228}
229
230static void
231test_param(void *s __unused, int cmd, unsigned int value)
232{
233
234	switch (cmd) {
235	case TP_SHOWCURSOR:
236		curs_set(value);
237		break;
238	case TP_KEYPADAPP:
239		keypad(stdscr, value ? TRUE : FALSE);
240		break;
241	}
242}
243
244static void
245test_respond(void *s __unused, const void *buf, size_t len)
246{
247
248	write(ptfd, buf, len);
249}
250
251static void
252redraw_border(void)
253{
254	unsigned int i;
255
256	for (i = 0; i < NROWS; i++)
257		mvaddch(i, NCOLS, '|');
258	for (i = 0; i < NCOLS; i++)
259		mvaddch(NROWS, i, '-');
260
261	mvaddch(NROWS, NCOLS, '+');
262}
263
264static void
265redraw_all(void)
266{
267	teken_pos_t tp;
268
269	for (tp.tp_row = 0; tp.tp_row < NROWS; tp.tp_row++)
270		for (tp.tp_col = 0; tp.tp_col < NCOLS; tp.tp_col++)
271			printchar(&tp);
272
273	redraw_border();
274}
275
276int
277main(int argc __unused, char *argv[] __unused)
278{
279	struct winsize ws;
280	teken_t t;
281	teken_pos_t tp;
282	fd_set rfds;
283	char b[256];
284	ssize_t bl;
285	const int ccolors[8] = {
286	    COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW,
287	    COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE
288	};
289	int i, j;
290
291	setlocale(LC_CTYPE, "UTF-8");
292
293	tp.tp_row = ws.ws_row = NROWS;
294	tp.tp_col = ws.ws_col = NCOLS;
295
296	switch (forkpty(&ptfd, NULL, NULL, &ws)) {
297	case -1:
298		perror("forkpty");
299		exit(1);
300	case 0:
301		setenv("TERM", "xterm", 1);
302		setenv("LC_CTYPE", "UTF-8", 0);
303		execlp("zsh", "-zsh", NULL);
304		execlp("bash", "-bash", NULL);
305		execlp("sh", "-sh", NULL);
306		_exit(1);
307	}
308
309	teken_init(&t, &tf, NULL);
310	teken_set_winsize(&t, &tp);
311
312	initscr();
313	raw();
314	start_color();
315	for (i = 0; i < 8; i++)
316		for (j = 0; j < 8; j++)
317			init_pair(i + 8 * j, ccolors[i], ccolors[j]);
318
319	redraw_border();
320
321	FD_ZERO(&rfds);
322
323	for (;;) {
324		FD_SET(STDIN_FILENO, &rfds);
325		FD_SET(ptfd, &rfds);
326
327		if (select(ptfd + 1, &rfds, NULL, NULL, NULL) < 0) {
328			if (errno == EINTR) {
329				redraw_all();
330				refresh();
331				continue;
332			}
333			break;
334		}
335
336		if (FD_ISSET(STDIN_FILENO, &rfds)) {
337			bl = read(STDIN_FILENO, b, sizeof b);
338			if (bl <= 0)
339				break;
340			write(ptfd, b, bl);
341		}
342
343		if (FD_ISSET(ptfd, &rfds)) {
344			bl = read(ptfd, b, sizeof b);
345			if (bl <= 0)
346				break;
347			teken_input(&t, b, bl);
348			refresh();
349		}
350	}
351
352	endwin();
353
354	return (0);
355}
356