teken_demo.c revision 221698
1186681Sed/*-
2186681Sed * Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org>
3186681Sed * All rights reserved.
4186681Sed *
5186681Sed * Redistribution and use in source and binary forms, with or without
6186681Sed * modification, are permitted provided that the following conditions
7186681Sed * are met:
8186681Sed * 1. Redistributions of source code must retain the above copyright
9186681Sed *    notice, this list of conditions and the following disclaimer.
10186681Sed * 2. Redistributions in binary form must reproduce the above copyright
11186681Sed *    notice, this list of conditions and the following disclaimer in the
12186681Sed *    documentation and/or other materials provided with the distribution.
13186681Sed *
14186681Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15186681Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16186681Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17186681Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18186681Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19186681Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20186681Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21186681Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22186681Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23186681Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24186681Sed * SUCH DAMAGE.
25186681Sed *
26186681Sed * $FreeBSD: head/sys/teken/demo/teken_demo.c 221698 2011-05-09 16:27:39Z ed $
27186681Sed */
28186681Sed
29186681Sed#include <sys/ioctl.h>
30186681Sed
31186681Sed#include <assert.h>
32186681Sed#include <errno.h>
33186681Sed#include <inttypes.h>
34187562Sed#include <locale.h>
35186681Sed#include <stdio.h>
36186681Sed#include <stdlib.h>
37186681Sed#include <unistd.h>
38186681Sed
39186681Sed#include <ncurses.h>
40186681Sed#if defined(__FreeBSD__)
41186681Sed#include <libutil.h>
42186681Sed#elif defined(__linux__)
43186681Sed#include <pty.h>
44186681Sed#else
45186681Sed#include <util.h>
46186681Sed#endif
47186681Sed
48221698Sed#include <teken.h>
49186681Sed
50186681Sedstatic tf_bell_t	test_bell;
51186681Sedstatic tf_cursor_t	test_cursor;
52186681Sedstatic tf_putchar_t	test_putchar;
53186681Sedstatic tf_fill_t	test_fill;
54186681Sedstatic tf_copy_t	test_copy;
55186681Sedstatic tf_param_t	test_param;
56186681Sedstatic tf_respond_t	test_respond;
57186681Sed
58186681Sedstatic teken_funcs_t tf = {
59186681Sed	.tf_bell	= test_bell,
60186681Sed	.tf_cursor	= test_cursor,
61186681Sed	.tf_putchar	= test_putchar,
62186681Sed	.tf_fill	= test_fill,
63186681Sed	.tf_copy	= test_copy,
64186681Sed	.tf_param	= test_param,
65186681Sed	.tf_respond	= test_respond,
66186681Sed};
67186681Sed
68186681Sedstruct pixel {
69186681Sed	teken_char_t	c;
70186681Sed	teken_attr_t	a;
71186681Sed};
72186681Sed
73186681Sed#define NCOLS	80
74187469Sed#define NROWS	24
75186681Sedstruct pixel buffer[NCOLS][NROWS];
76186681Sed
77186681Sedstatic int ptfd;
78186681Sed
79186681Sedstatic void
80186681Sedprintchar(const teken_pos_t *p)
81186681Sed{
82186681Sed	int y, x, attr = 0;
83187562Sed	struct pixel *px;
84187562Sed	char str[5] = { 0 };
85186681Sed
86186681Sed	assert(p->tp_row < NROWS);
87186681Sed	assert(p->tp_col < NCOLS);
88186681Sed
89186681Sed	getyx(stdscr, y, x);
90186681Sed
91186681Sed 	px = &buffer[p->tp_col][p->tp_row];
92186681Sed
93187562Sed	/* Convert Unicode to UTF-8. */
94187562Sed	if (px->c < 0x80) {
95187562Sed		str[0] = px->c;
96187562Sed	} else if (px->c < 0x800) {
97187562Sed		str[0] = 0xc0 | (px->c >> 6);
98187562Sed		str[1] = 0x80 | (px->c & 0x3f);
99187562Sed	} else if (px->c < 0x10000) {
100187562Sed		str[0] = 0xe0 | (px->c >> 12);
101187562Sed		str[1] = 0x80 | ((px->c >> 6) & 0x3f);
102187562Sed		str[2] = 0x80 | (px->c & 0x3f);
103187562Sed	} else {
104187562Sed		str[0] = 0xf0 | (px->c >> 18);
105187562Sed		str[1] = 0x80 | ((px->c >> 12) & 0x3f);
106187562Sed		str[2] = 0x80 | ((px->c >> 6) & 0x3f);
107187562Sed		str[3] = 0x80 | (px->c & 0x3f);
108186681Sed	}
109186681Sed
110186681Sed	if (px->a.ta_format & TF_BOLD)
111186681Sed		attr |= A_BOLD;
112186681Sed	if (px->a.ta_format & TF_UNDERLINE)
113186681Sed		attr |= A_UNDERLINE;
114186681Sed	if (px->a.ta_format & TF_BLINK)
115186681Sed		attr |= A_BLINK;
116196786Sed	if (px->a.ta_format & TF_REVERSE)
117196786Sed		attr |= A_REVERSE;
118186681Sed
119197522Sed	bkgdset(attr | COLOR_PAIR(teken_256to8(px->a.ta_fgcolor) +
120197522Sed	      8 * teken_256to8(px->a.ta_bgcolor)));
121187562Sed	mvaddstr(p->tp_row, p->tp_col, str);
122186681Sed
123186681Sed	move(y, x);
124186681Sed}
125186681Sed
126186681Sedstatic void
127186681Sedtest_bell(void *s __unused)
128186681Sed{
129186681Sed
130186681Sed	beep();
131186681Sed}
132186681Sed
133186681Sedstatic void
134186681Sedtest_cursor(void *s __unused, const teken_pos_t *p)
135186681Sed{
136186681Sed
137186681Sed	move(p->tp_row, p->tp_col);
138186681Sed}
139186681Sed
140186681Sedstatic void
141186681Sedtest_putchar(void *s __unused, const teken_pos_t *p, teken_char_t c,
142186681Sed    const teken_attr_t *a)
143186681Sed{
144186681Sed
145186681Sed	buffer[p->tp_col][p->tp_row].c = c;
146186681Sed	buffer[p->tp_col][p->tp_row].a = *a;
147186681Sed	printchar(p);
148186681Sed}
149186681Sed
150186681Sedstatic void
151186681Sedtest_fill(void *s, const teken_rect_t *r, teken_char_t c,
152186681Sed    const teken_attr_t *a)
153186681Sed{
154186681Sed	teken_pos_t p;
155186681Sed
156186681Sed	/* Braindead implementation of fill() - just call putchar(). */
157186681Sed	for (p.tp_row = r->tr_begin.tp_row; p.tp_row < r->tr_end.tp_row; p.tp_row++)
158186681Sed		for (p.tp_col = r->tr_begin.tp_col; p.tp_col < r->tr_end.tp_col; p.tp_col++)
159186681Sed			test_putchar(s, &p, c, a);
160186681Sed}
161186681Sed
162186681Sedstatic void
163186681Sedtest_copy(void *s __unused, const teken_rect_t *r, const teken_pos_t *p)
164186681Sed{
165186681Sed	int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */
166186681Sed	teken_pos_t d;
167186681Sed
168186681Sed	/*
169186681Sed	 * Copying is a little tricky. We must make sure we do it in
170186681Sed	 * correct order, to make sure we don't overwrite our own data.
171186681Sed	 */
172186681Sed
173186681Sed	nrow = r->tr_end.tp_row - r->tr_begin.tp_row;
174186681Sed	ncol = r->tr_end.tp_col - r->tr_begin.tp_col;
175186681Sed
176186681Sed	if (p->tp_row < r->tr_begin.tp_row) {
177186681Sed		/* Copy from top to bottom. */
178186681Sed		if (p->tp_col < r->tr_begin.tp_col) {
179186681Sed			/* Copy from left to right. */
180186681Sed			for (y = 0; y < nrow; y++) {
181186681Sed				d.tp_row = p->tp_row + y;
182186681Sed				for (x = 0; x < ncol; x++) {
183186681Sed					d.tp_col = p->tp_col + x;
184186681Sed					buffer[d.tp_col][d.tp_row] =
185186681Sed					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
186186681Sed					printchar(&d);
187186681Sed				}
188186681Sed			}
189186681Sed		} else {
190186681Sed			/* Copy from right to left. */
191186681Sed			for (y = 0; y < nrow; y++) {
192186681Sed				d.tp_row = p->tp_row + y;
193186681Sed				for (x = ncol - 1; x >= 0; x--) {
194186681Sed					d.tp_col = p->tp_col + x;
195186681Sed					buffer[d.tp_col][d.tp_row] =
196186681Sed					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
197186681Sed					printchar(&d);
198186681Sed				}
199186681Sed			}
200186681Sed		}
201186681Sed	} else {
202186681Sed		/* Copy from bottom to top. */
203186681Sed		if (p->tp_col < r->tr_begin.tp_col) {
204186681Sed			/* Copy from left to right. */
205186681Sed			for (y = nrow - 1; y >= 0; y--) {
206186681Sed				d.tp_row = p->tp_row + y;
207186681Sed				for (x = 0; x < ncol; x++) {
208186681Sed					d.tp_col = p->tp_col + x;
209186681Sed					buffer[d.tp_col][d.tp_row] =
210186681Sed					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
211186681Sed					printchar(&d);
212186681Sed				}
213186681Sed			}
214186681Sed		} else {
215186681Sed			/* Copy from right to left. */
216186681Sed			for (y = nrow - 1; y >= 0; y--) {
217186681Sed				d.tp_row = p->tp_row + y;
218186681Sed				for (x = ncol - 1; x >= 0; x--) {
219186681Sed					d.tp_col = p->tp_col + x;
220186681Sed					buffer[d.tp_col][d.tp_row] =
221186681Sed					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
222186681Sed					printchar(&d);
223186681Sed				}
224186681Sed			}
225186681Sed		}
226186681Sed	}
227186681Sed}
228186681Sed
229186681Sedstatic void
230193940Sedtest_param(void *s __unused, int cmd, unsigned int value)
231186681Sed{
232186681Sed
233186681Sed	switch (cmd) {
234186681Sed	case TP_SHOWCURSOR:
235186681Sed		curs_set(value);
236186681Sed		break;
237186681Sed	case TP_KEYPADAPP:
238186681Sed		keypad(stdscr, value ? TRUE : FALSE);
239186681Sed		break;
240186681Sed	}
241186681Sed}
242186681Sed
243186681Sedstatic void
244186681Sedtest_respond(void *s __unused, const void *buf, size_t len)
245186681Sed{
246186681Sed
247186681Sed	write(ptfd, buf, len);
248186681Sed}
249186681Sed
250186681Sedstatic void
251186681Sedredraw_border(void)
252186681Sed{
253186681Sed	unsigned int i;
254186681Sed
255186681Sed	for (i = 0; i < NROWS; i++)
256186681Sed		mvaddch(i, NCOLS, '|');
257186681Sed	for (i = 0; i < NCOLS; i++)
258186681Sed		mvaddch(NROWS, i, '-');
259186681Sed
260186681Sed	mvaddch(NROWS, NCOLS, '+');
261186681Sed}
262186681Sed
263186681Sedstatic void
264186681Sedredraw_all(void)
265186681Sed{
266186681Sed	teken_pos_t tp;
267186681Sed
268186681Sed	for (tp.tp_row = 0; tp.tp_row < NROWS; tp.tp_row++)
269186681Sed		for (tp.tp_col = 0; tp.tp_col < NCOLS; tp.tp_col++)
270186681Sed			printchar(&tp);
271186681Sed
272186681Sed	redraw_border();
273186681Sed}
274186681Sed
275186681Sedint
276186681Sedmain(int argc __unused, char *argv[] __unused)
277186681Sed{
278186681Sed	struct winsize ws;
279186681Sed	teken_t t;
280186681Sed	teken_pos_t tp;
281186681Sed	fd_set rfds;
282186681Sed	char b[256];
283186681Sed	ssize_t bl;
284187562Sed	const int ccolors[8] = {
285187562Sed	    COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW,
286187562Sed	    COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE
287187562Sed	};
288186681Sed	int i, j;
289186681Sed
290187562Sed	setlocale(LC_CTYPE, "UTF-8");
291187562Sed
292186681Sed	tp.tp_row = ws.ws_row = NROWS;
293186681Sed	tp.tp_col = ws.ws_col = NCOLS;
294186681Sed
295186681Sed	switch (forkpty(&ptfd, NULL, NULL, &ws)) {
296186681Sed	case -1:
297186681Sed		perror("forkpty");
298186681Sed		exit(1);
299186681Sed	case 0:
300187367Sed		setenv("TERM", "xterm", 1);
301186681Sed		setenv("LC_CTYPE", "UTF-8", 0);
302186681Sed		execlp("zsh", "-zsh", NULL);
303186681Sed		execlp("bash", "-bash", NULL);
304186681Sed		execlp("sh", "-sh", NULL);
305186681Sed		_exit(1);
306186681Sed	}
307186681Sed
308186681Sed	teken_init(&t, &tf, NULL);
309186681Sed	teken_set_winsize(&t, &tp);
310186681Sed
311186681Sed	initscr();
312186681Sed	raw();
313186681Sed	start_color();
314186681Sed	for (i = 0; i < 8; i++)
315186681Sed		for (j = 0; j < 8; j++)
316187469Sed			init_pair(i + 8 * j, ccolors[i], ccolors[j]);
317186681Sed
318186681Sed	redraw_border();
319186681Sed
320186681Sed	FD_ZERO(&rfds);
321186681Sed
322186681Sed	for (;;) {
323186681Sed		FD_SET(STDIN_FILENO, &rfds);
324186681Sed		FD_SET(ptfd, &rfds);
325186681Sed
326186681Sed		if (select(ptfd + 1, &rfds, NULL, NULL, NULL) < 0) {
327186681Sed			if (errno == EINTR) {
328186681Sed				redraw_all();
329186681Sed				refresh();
330186681Sed				continue;
331186681Sed			}
332186681Sed			break;
333186681Sed		}
334186681Sed
335186681Sed		if (FD_ISSET(STDIN_FILENO, &rfds)) {
336186681Sed			bl = read(STDIN_FILENO, b, sizeof b);
337186681Sed			if (bl <= 0)
338186681Sed				break;
339186681Sed			write(ptfd, b, bl);
340186681Sed		}
341186681Sed
342186681Sed		if (FD_ISSET(ptfd, &rfds)) {
343186681Sed			bl = read(ptfd, b, sizeof b);
344186681Sed			if (bl <= 0)
345186681Sed				break;
346186681Sed			teken_input(&t, b, bl);
347186681Sed			refresh();
348186681Sed		}
349186681Sed	}
350186681Sed
351186681Sed	endwin();
352186681Sed
353186681Sed	return (0);
354186681Sed}
355