teken_demo.c revision 187469
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/dev/syscons/teken/teken_demo.c 187469 2009-01-20 11:34:28Z ed $
27186681Sed */
28186681Sed
29186681Sed#include <sys/ioctl.h>
30186681Sed
31186681Sed#include <assert.h>
32186681Sed#include <errno.h>
33186681Sed#include <inttypes.h>
34186681Sed#include <stdio.h>
35186681Sed#include <stdlib.h>
36186681Sed#include <unistd.h>
37186681Sed
38186681Sed#include <ncurses.h>
39186681Sed#if defined(__FreeBSD__)
40186681Sed#include <libutil.h>
41186681Sed#elif defined(__linux__)
42186681Sed#include <pty.h>
43186681Sed#else
44186681Sed#include <util.h>
45186681Sed#endif
46186681Sed
47186681Sed#include "teken.h"
48186681Sed
49186681Sedstatic tf_bell_t	test_bell;
50186681Sedstatic tf_cursor_t	test_cursor;
51186681Sedstatic tf_putchar_t	test_putchar;
52186681Sedstatic tf_fill_t	test_fill;
53186681Sedstatic tf_copy_t	test_copy;
54186681Sedstatic tf_param_t	test_param;
55186681Sedstatic tf_respond_t	test_respond;
56186681Sed
57186681Sedstatic teken_funcs_t tf = {
58186681Sed	.tf_bell	= test_bell,
59186681Sed	.tf_cursor	= test_cursor,
60186681Sed	.tf_putchar	= test_putchar,
61186681Sed	.tf_fill	= test_fill,
62186681Sed	.tf_copy	= test_copy,
63186681Sed	.tf_param	= test_param,
64186681Sed	.tf_respond	= test_respond,
65186681Sed};
66186681Sed
67186681Sedstruct pixel {
68186681Sed	teken_char_t	c;
69186681Sed	teken_attr_t	a;
70186681Sed};
71186681Sed
72186681Sed#define NCOLS	80
73187469Sed#ifdef TEKEN_XTERM
74187469Sed#define NROWS	24
75187469Sed#else /* !TEKEN_XTERM */
76186729Sed#define NROWS	25
77187469Sed#endif /* TEKEN_XTERM */
78186681Sedstruct pixel buffer[NCOLS][NROWS];
79186681Sed
80186681Sedstatic int ptfd;
81186681Sed
82186681Sedstatic void
83186681Sedprintchar(const teken_pos_t *p)
84186681Sed{
85186681Sed	int y, x, attr = 0;
86186681Sed	struct pixel *px, pt;
87186681Sed
88186681Sed	assert(p->tp_row < NROWS);
89186681Sed	assert(p->tp_col < NCOLS);
90186681Sed
91186681Sed	getyx(stdscr, y, x);
92186681Sed
93186681Sed 	px = &buffer[p->tp_col][p->tp_row];
94186681Sed
95186681Sed	if (px->c >= 0x80) {
96186681Sed		/* Mark UTF-8 chars (we don't support it). */
97186681Sed		px = &pt;
98186681Sed		px->c = '?';
99186681Sed		px->a.ta_format = TF_BOLD;
100186681Sed		px->a.ta_fgcolor = TC_BROWN;
101186681Sed		px->a.ta_bgcolor = TC_RED;
102186681Sed	}
103186681Sed
104186681Sed	if (px->a.ta_format & TF_BOLD)
105186681Sed		attr |= A_BOLD;
106186681Sed	if (px->a.ta_format & TF_UNDERLINE)
107186681Sed		attr |= A_UNDERLINE;
108186681Sed	if (px->a.ta_format & TF_BLINK)
109186681Sed		attr |= A_BLINK;
110186681Sed
111187469Sed	bkgdset(attr | COLOR_PAIR(px->a.ta_fgcolor + 8 * px->a.ta_bgcolor));
112186681Sed	mvaddch(p->tp_row, p->tp_col, px->c);
113186681Sed
114186681Sed	move(y, x);
115186681Sed}
116186681Sed
117186681Sedstatic void
118186681Sedtest_bell(void *s __unused)
119186681Sed{
120186681Sed
121186681Sed	beep();
122186681Sed}
123186681Sed
124186681Sedstatic void
125186681Sedtest_cursor(void *s __unused, const teken_pos_t *p)
126186681Sed{
127186681Sed
128186681Sed	move(p->tp_row, p->tp_col);
129186681Sed}
130186681Sed
131186681Sedstatic void
132186681Sedtest_putchar(void *s __unused, const teken_pos_t *p, teken_char_t c,
133186681Sed    const teken_attr_t *a)
134186681Sed{
135186681Sed
136186681Sed	buffer[p->tp_col][p->tp_row].c = c;
137186681Sed	buffer[p->tp_col][p->tp_row].a = *a;
138186681Sed	printchar(p);
139186681Sed}
140186681Sed
141186681Sedstatic void
142186681Sedtest_fill(void *s, const teken_rect_t *r, teken_char_t c,
143186681Sed    const teken_attr_t *a)
144186681Sed{
145186681Sed	teken_pos_t p;
146186681Sed
147186681Sed	/* Braindead implementation of fill() - just call putchar(). */
148186681Sed	for (p.tp_row = r->tr_begin.tp_row; p.tp_row < r->tr_end.tp_row; p.tp_row++)
149186681Sed		for (p.tp_col = r->tr_begin.tp_col; p.tp_col < r->tr_end.tp_col; p.tp_col++)
150186681Sed			test_putchar(s, &p, c, a);
151186681Sed}
152186681Sed
153186681Sedstatic void
154186681Sedtest_copy(void *s __unused, const teken_rect_t *r, const teken_pos_t *p)
155186681Sed{
156186681Sed	int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */
157186681Sed	teken_pos_t d;
158186681Sed
159186681Sed	/*
160186681Sed	 * Copying is a little tricky. We must make sure we do it in
161186681Sed	 * correct order, to make sure we don't overwrite our own data.
162186681Sed	 */
163186681Sed
164186681Sed	nrow = r->tr_end.tp_row - r->tr_begin.tp_row;
165186681Sed	ncol = r->tr_end.tp_col - r->tr_begin.tp_col;
166186681Sed
167186681Sed	if (p->tp_row < r->tr_begin.tp_row) {
168186681Sed		/* Copy from top to bottom. */
169186681Sed		if (p->tp_col < r->tr_begin.tp_col) {
170186681Sed			/* Copy from left to right. */
171186681Sed			for (y = 0; y < nrow; y++) {
172186681Sed				d.tp_row = p->tp_row + y;
173186681Sed				for (x = 0; x < ncol; x++) {
174186681Sed					d.tp_col = p->tp_col + x;
175186681Sed					buffer[d.tp_col][d.tp_row] =
176186681Sed					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
177186681Sed					printchar(&d);
178186681Sed				}
179186681Sed			}
180186681Sed		} else {
181186681Sed			/* Copy from right to left. */
182186681Sed			for (y = 0; y < nrow; y++) {
183186681Sed				d.tp_row = p->tp_row + y;
184186681Sed				for (x = ncol - 1; x >= 0; x--) {
185186681Sed					d.tp_col = p->tp_col + x;
186186681Sed					buffer[d.tp_col][d.tp_row] =
187186681Sed					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
188186681Sed					printchar(&d);
189186681Sed				}
190186681Sed			}
191186681Sed		}
192186681Sed	} else {
193186681Sed		/* Copy from bottom to top. */
194186681Sed		if (p->tp_col < r->tr_begin.tp_col) {
195186681Sed			/* Copy from left to right. */
196186681Sed			for (y = nrow - 1; y >= 0; y--) {
197186681Sed				d.tp_row = p->tp_row + y;
198186681Sed				for (x = 0; x < ncol; x++) {
199186681Sed					d.tp_col = p->tp_col + x;
200186681Sed					buffer[d.tp_col][d.tp_row] =
201186681Sed					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
202186681Sed					printchar(&d);
203186681Sed				}
204186681Sed			}
205186681Sed		} else {
206186681Sed			/* Copy from right to left. */
207186681Sed			for (y = nrow - 1; y >= 0; y--) {
208186681Sed				d.tp_row = p->tp_row + y;
209186681Sed				for (x = ncol - 1; x >= 0; x--) {
210186681Sed					d.tp_col = p->tp_col + x;
211186681Sed					buffer[d.tp_col][d.tp_row] =
212186681Sed					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
213186681Sed					printchar(&d);
214186681Sed				}
215186681Sed			}
216186681Sed		}
217186681Sed	}
218186681Sed}
219186681Sed
220186681Sedstatic void
221186681Sedtest_param(void *s __unused, int cmd, int value)
222186681Sed{
223186681Sed
224186681Sed	switch (cmd) {
225186681Sed	case TP_SHOWCURSOR:
226186681Sed		curs_set(value);
227186681Sed		break;
228186681Sed	case TP_KEYPADAPP:
229186681Sed		keypad(stdscr, value ? TRUE : FALSE);
230186681Sed		break;
231186681Sed	}
232186681Sed}
233186681Sed
234186681Sedstatic void
235186681Sedtest_respond(void *s __unused, const void *buf, size_t len)
236186681Sed{
237186681Sed
238186681Sed	write(ptfd, buf, len);
239186681Sed}
240186681Sed
241186681Sedstatic void
242186681Sedredraw_border(void)
243186681Sed{
244186681Sed	unsigned int i;
245186681Sed
246186681Sed	for (i = 0; i < NROWS; i++)
247186681Sed		mvaddch(i, NCOLS, '|');
248186681Sed	for (i = 0; i < NCOLS; i++)
249186681Sed		mvaddch(NROWS, i, '-');
250186681Sed
251186681Sed	mvaddch(NROWS, NCOLS, '+');
252186681Sed}
253186681Sed
254186681Sedstatic void
255186681Sedredraw_all(void)
256186681Sed{
257186681Sed	teken_pos_t tp;
258186681Sed
259186681Sed	for (tp.tp_row = 0; tp.tp_row < NROWS; tp.tp_row++)
260186681Sed		for (tp.tp_col = 0; tp.tp_col < NCOLS; tp.tp_col++)
261186681Sed			printchar(&tp);
262186681Sed
263186681Sed	redraw_border();
264186681Sed}
265186681Sed
266186681Sedint
267186681Sedmain(int argc __unused, char *argv[] __unused)
268186681Sed{
269186681Sed	struct winsize ws;
270186681Sed	teken_t t;
271186681Sed	teken_pos_t tp;
272186681Sed	fd_set rfds;
273186681Sed	char b[256];
274186681Sed	ssize_t bl;
275186681Sed	const int ccolors[8] = { COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE };
276186681Sed	int i, j;
277186681Sed
278186681Sed	tp.tp_row = ws.ws_row = NROWS;
279186681Sed	tp.tp_col = ws.ws_col = NCOLS;
280186681Sed
281186681Sed	switch (forkpty(&ptfd, NULL, NULL, &ws)) {
282186681Sed	case -1:
283186681Sed		perror("forkpty");
284186681Sed		exit(1);
285186681Sed	case 0:
286187367Sed#ifdef TEKEN_XTERM
287187367Sed		setenv("TERM", "xterm", 1);
288187367Sed#else /* !TEKEN_XTERM */
289186729Sed		setenv("TERM", "cons25", 1);
290187367Sed#endif /* TEKEN_XTERM */
291186731Sed#ifdef TEKEN_UTF8
292186681Sed		setenv("LC_CTYPE", "UTF-8", 0);
293186731Sed#endif /* TEKEN_UTF8 */
294186681Sed		execlp("zsh", "-zsh", NULL);
295186681Sed		execlp("bash", "-bash", NULL);
296186681Sed		execlp("sh", "-sh", NULL);
297186681Sed		_exit(1);
298186681Sed	}
299186681Sed
300186681Sed	teken_init(&t, &tf, NULL);
301186681Sed	teken_set_winsize(&t, &tp);
302186681Sed
303186681Sed	initscr();
304186681Sed	raw();
305186681Sed	start_color();
306186681Sed	for (i = 0; i < 8; i++)
307186681Sed		for (j = 0; j < 8; j++)
308187469Sed			init_pair(i + 8 * j, ccolors[i], ccolors[j]);
309186681Sed
310186681Sed	redraw_border();
311186681Sed
312186681Sed	FD_ZERO(&rfds);
313186681Sed
314186681Sed	for (;;) {
315186681Sed		FD_SET(STDIN_FILENO, &rfds);
316186681Sed		FD_SET(ptfd, &rfds);
317186681Sed
318186681Sed		if (select(ptfd + 1, &rfds, NULL, NULL, NULL) < 0) {
319186681Sed			if (errno == EINTR) {
320186681Sed				redraw_all();
321186681Sed				refresh();
322186681Sed				continue;
323186681Sed			}
324186681Sed			break;
325186681Sed		}
326186681Sed
327186681Sed		if (FD_ISSET(STDIN_FILENO, &rfds)) {
328186681Sed			bl = read(STDIN_FILENO, b, sizeof b);
329186681Sed			if (bl <= 0)
330186681Sed				break;
331186681Sed			write(ptfd, b, bl);
332186681Sed		}
333186681Sed
334186681Sed		if (FD_ISSET(ptfd, &rfds)) {
335186681Sed			bl = read(ptfd, b, sizeof b);
336186681Sed			if (bl <= 0)
337186681Sed				break;
338186681Sed			teken_input(&t, b, bl);
339186681Sed			refresh();
340186681Sed		}
341186681Sed	}
342186681Sed
343186681Sed	endwin();
344186681Sed
345186681Sed	return (0);
346186681Sed}
347