teken_demo.c revision 193940
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: head/sys/dev/syscons/teken/teken_demo.c 193940 2009-06-10 18:26:02Z ed $
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#ifdef TEKEN_XTERM
75#define NROWS	24
76#else /* !TEKEN_XTERM */
77#define NROWS	25
78#endif /* TEKEN_XTERM */
79struct pixel buffer[NCOLS][NROWS];
80
81static int ptfd;
82
83static void
84printchar(const teken_pos_t *p)
85{
86	int y, x, attr = 0;
87	struct pixel *px;
88	char str[5] = { 0 };
89
90	assert(p->tp_row < NROWS);
91	assert(p->tp_col < NCOLS);
92
93	getyx(stdscr, y, x);
94
95 	px = &buffer[p->tp_col][p->tp_row];
96
97	/* Convert Unicode to UTF-8. */
98#ifdef TEKEN_UTF8
99	if (px->c < 0x80) {
100		str[0] = px->c;
101	} else if (px->c < 0x800) {
102		str[0] = 0xc0 | (px->c >> 6);
103		str[1] = 0x80 | (px->c & 0x3f);
104	} else if (px->c < 0x10000) {
105		str[0] = 0xe0 | (px->c >> 12);
106		str[1] = 0x80 | ((px->c >> 6) & 0x3f);
107		str[2] = 0x80 | (px->c & 0x3f);
108	} else {
109		str[0] = 0xf0 | (px->c >> 18);
110		str[1] = 0x80 | ((px->c >> 12) & 0x3f);
111		str[2] = 0x80 | ((px->c >> 6) & 0x3f);
112		str[3] = 0x80 | (px->c & 0x3f);
113	}
114#else /* !TEKEN_UTF8 */
115	str[0] = px->c;
116#endif /* TEKEN_UTF8 */
117
118	if (px->a.ta_format & TF_BOLD)
119		attr |= A_BOLD;
120	if (px->a.ta_format & TF_UNDERLINE)
121		attr |= A_UNDERLINE;
122	if (px->a.ta_format & TF_BLINK)
123		attr |= A_BLINK;
124
125	bkgdset(attr | COLOR_PAIR(px->a.ta_fgcolor + 8 * px->a.ta_bgcolor));
126	mvaddstr(p->tp_row, p->tp_col, str);
127
128	move(y, x);
129}
130
131static void
132test_bell(void *s __unused)
133{
134
135	beep();
136}
137
138static void
139test_cursor(void *s __unused, const teken_pos_t *p)
140{
141
142	move(p->tp_row, p->tp_col);
143}
144
145static void
146test_putchar(void *s __unused, const teken_pos_t *p, teken_char_t c,
147    const teken_attr_t *a)
148{
149
150	buffer[p->tp_col][p->tp_row].c = c;
151	buffer[p->tp_col][p->tp_row].a = *a;
152	printchar(p);
153}
154
155static void
156test_fill(void *s, const teken_rect_t *r, teken_char_t c,
157    const teken_attr_t *a)
158{
159	teken_pos_t p;
160
161	/* Braindead implementation of fill() - just call putchar(). */
162	for (p.tp_row = r->tr_begin.tp_row; p.tp_row < r->tr_end.tp_row; p.tp_row++)
163		for (p.tp_col = r->tr_begin.tp_col; p.tp_col < r->tr_end.tp_col; p.tp_col++)
164			test_putchar(s, &p, c, a);
165}
166
167static void
168test_copy(void *s __unused, const teken_rect_t *r, const teken_pos_t *p)
169{
170	int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */
171	teken_pos_t d;
172
173	/*
174	 * Copying is a little tricky. We must make sure we do it in
175	 * correct order, to make sure we don't overwrite our own data.
176	 */
177
178	nrow = r->tr_end.tp_row - r->tr_begin.tp_row;
179	ncol = r->tr_end.tp_col - r->tr_begin.tp_col;
180
181	if (p->tp_row < r->tr_begin.tp_row) {
182		/* Copy from top to bottom. */
183		if (p->tp_col < r->tr_begin.tp_col) {
184			/* Copy from left to right. */
185			for (y = 0; y < nrow; y++) {
186				d.tp_row = p->tp_row + y;
187				for (x = 0; x < ncol; x++) {
188					d.tp_col = p->tp_col + x;
189					buffer[d.tp_col][d.tp_row] =
190					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
191					printchar(&d);
192				}
193			}
194		} else {
195			/* Copy from right to left. */
196			for (y = 0; y < nrow; y++) {
197				d.tp_row = p->tp_row + y;
198				for (x = ncol - 1; x >= 0; x--) {
199					d.tp_col = p->tp_col + x;
200					buffer[d.tp_col][d.tp_row] =
201					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
202					printchar(&d);
203				}
204			}
205		}
206	} else {
207		/* Copy from bottom to top. */
208		if (p->tp_col < r->tr_begin.tp_col) {
209			/* Copy from left to right. */
210			for (y = nrow - 1; y >= 0; y--) {
211				d.tp_row = p->tp_row + y;
212				for (x = 0; x < ncol; x++) {
213					d.tp_col = p->tp_col + x;
214					buffer[d.tp_col][d.tp_row] =
215					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
216					printchar(&d);
217				}
218			}
219		} else {
220			/* Copy from right to left. */
221			for (y = nrow - 1; y >= 0; y--) {
222				d.tp_row = p->tp_row + y;
223				for (x = ncol - 1; x >= 0; x--) {
224					d.tp_col = p->tp_col + x;
225					buffer[d.tp_col][d.tp_row] =
226					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
227					printchar(&d);
228				}
229			}
230		}
231	}
232}
233
234static void
235test_param(void *s __unused, int cmd, unsigned int value)
236{
237
238	switch (cmd) {
239	case TP_SHOWCURSOR:
240		curs_set(value);
241		break;
242	case TP_KEYPADAPP:
243		keypad(stdscr, value ? TRUE : FALSE);
244		break;
245	}
246}
247
248static void
249test_respond(void *s __unused, const void *buf, size_t len)
250{
251
252	write(ptfd, buf, len);
253}
254
255static void
256redraw_border(void)
257{
258	unsigned int i;
259
260	for (i = 0; i < NROWS; i++)
261		mvaddch(i, NCOLS, '|');
262	for (i = 0; i < NCOLS; i++)
263		mvaddch(NROWS, i, '-');
264
265	mvaddch(NROWS, NCOLS, '+');
266}
267
268static void
269redraw_all(void)
270{
271	teken_pos_t tp;
272
273	for (tp.tp_row = 0; tp.tp_row < NROWS; tp.tp_row++)
274		for (tp.tp_col = 0; tp.tp_col < NCOLS; tp.tp_col++)
275			printchar(&tp);
276
277	redraw_border();
278}
279
280int
281main(int argc __unused, char *argv[] __unused)
282{
283	struct winsize ws;
284	teken_t t;
285	teken_pos_t tp;
286	fd_set rfds;
287	char b[256];
288	ssize_t bl;
289	const int ccolors[8] = {
290	    COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW,
291	    COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE
292	};
293	int i, j;
294
295#ifdef TEKEN_UTF8
296	setlocale(LC_CTYPE, "UTF-8");
297#endif /* TEKEN_UTF8 */
298
299	tp.tp_row = ws.ws_row = NROWS;
300	tp.tp_col = ws.ws_col = NCOLS;
301
302	switch (forkpty(&ptfd, NULL, NULL, &ws)) {
303	case -1:
304		perror("forkpty");
305		exit(1);
306	case 0:
307#ifdef TEKEN_XTERM
308		setenv("TERM", "xterm", 1);
309#else /* !TEKEN_XTERM */
310		setenv("TERM", "cons25", 1);
311#endif /* TEKEN_XTERM */
312#ifdef TEKEN_UTF8
313		setenv("LC_CTYPE", "UTF-8", 0);
314#endif /* TEKEN_UTF8 */
315		execlp("zsh", "-zsh", NULL);
316		execlp("bash", "-bash", NULL);
317		execlp("sh", "-sh", NULL);
318		_exit(1);
319	}
320
321	teken_init(&t, &tf, NULL);
322	teken_set_winsize(&t, &tp);
323
324	initscr();
325	raw();
326	start_color();
327	for (i = 0; i < 8; i++)
328		for (j = 0; j < 8; j++)
329			init_pair(i + 8 * j, ccolors[i], ccolors[j]);
330
331	redraw_border();
332
333	FD_ZERO(&rfds);
334
335	for (;;) {
336		FD_SET(STDIN_FILENO, &rfds);
337		FD_SET(ptfd, &rfds);
338
339		if (select(ptfd + 1, &rfds, NULL, NULL, NULL) < 0) {
340			if (errno == EINTR) {
341				redraw_all();
342				refresh();
343				continue;
344			}
345			break;
346		}
347
348		if (FD_ISSET(STDIN_FILENO, &rfds)) {
349			bl = read(STDIN_FILENO, b, sizeof b);
350			if (bl <= 0)
351				break;
352			write(ptfd, b, bl);
353		}
354
355		if (FD_ISSET(ptfd, &rfds)) {
356			bl = read(ptfd, b, sizeof b);
357			if (bl <= 0)
358				break;
359			teken_input(&t, b, bl);
360			refresh();
361		}
362	}
363
364	endwin();
365
366	return (0);
367}
368