teken_demo.c revision 186681
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 186681 2009-01-01 13:26:53Z 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
73186681Sed#define NROWS	24
74186681Sedstruct pixel buffer[NCOLS][NROWS];
75186681Sed
76186681Sedstatic int ptfd;
77186681Sed
78186681Sedstatic void
79186681Sedprintchar(const teken_pos_t *p)
80186681Sed{
81186681Sed	int y, x, attr = 0;
82186681Sed	struct pixel *px, pt;
83186681Sed
84186681Sed	assert(p->tp_row < NROWS);
85186681Sed	assert(p->tp_col < NCOLS);
86186681Sed
87186681Sed	getyx(stdscr, y, x);
88186681Sed
89186681Sed 	px = &buffer[p->tp_col][p->tp_row];
90186681Sed
91186681Sed	if (px->c >= 0x80) {
92186681Sed		/* Mark UTF-8 chars (we don't support it). */
93186681Sed		px = &pt;
94186681Sed		px->c = '?';
95186681Sed		px->a.ta_format = TF_BOLD;
96186681Sed		px->a.ta_fgcolor = TC_BROWN;
97186681Sed		px->a.ta_bgcolor = TC_RED;
98186681Sed	}
99186681Sed
100186681Sed	if (px->a.ta_format & TF_BOLD)
101186681Sed		attr |= A_BOLD;
102186681Sed	if (px->a.ta_format & TF_UNDERLINE)
103186681Sed		attr |= A_UNDERLINE;
104186681Sed	if (px->a.ta_format & TF_BLINK)
105186681Sed		attr |= A_BLINK;
106186681Sed
107186681Sed	bkgdset(attr | COLOR_PAIR(px->a.ta_fgcolor + 8 * px->a.ta_bgcolor + 1));
108186681Sed	mvaddch(p->tp_row, p->tp_col, px->c);
109186681Sed
110186681Sed	move(y, x);
111186681Sed}
112186681Sed
113186681Sedstatic void
114186681Sedtest_bell(void *s __unused)
115186681Sed{
116186681Sed
117186681Sed	beep();
118186681Sed}
119186681Sed
120186681Sedstatic void
121186681Sedtest_cursor(void *s __unused, const teken_pos_t *p)
122186681Sed{
123186681Sed
124186681Sed	move(p->tp_row, p->tp_col);
125186681Sed}
126186681Sed
127186681Sedstatic void
128186681Sedtest_putchar(void *s __unused, const teken_pos_t *p, teken_char_t c,
129186681Sed    const teken_attr_t *a)
130186681Sed{
131186681Sed
132186681Sed	buffer[p->tp_col][p->tp_row].c = c;
133186681Sed	buffer[p->tp_col][p->tp_row].a = *a;
134186681Sed	printchar(p);
135186681Sed}
136186681Sed
137186681Sedstatic void
138186681Sedtest_fill(void *s, const teken_rect_t *r, teken_char_t c,
139186681Sed    const teken_attr_t *a)
140186681Sed{
141186681Sed	teken_pos_t p;
142186681Sed
143186681Sed	/* Braindead implementation of fill() - just call putchar(). */
144186681Sed	for (p.tp_row = r->tr_begin.tp_row; p.tp_row < r->tr_end.tp_row; p.tp_row++)
145186681Sed		for (p.tp_col = r->tr_begin.tp_col; p.tp_col < r->tr_end.tp_col; p.tp_col++)
146186681Sed			test_putchar(s, &p, c, a);
147186681Sed}
148186681Sed
149186681Sedstatic void
150186681Sedtest_copy(void *s __unused, const teken_rect_t *r, const teken_pos_t *p)
151186681Sed{
152186681Sed	int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */
153186681Sed	teken_pos_t d;
154186681Sed
155186681Sed	/*
156186681Sed	 * Copying is a little tricky. We must make sure we do it in
157186681Sed	 * correct order, to make sure we don't overwrite our own data.
158186681Sed	 */
159186681Sed
160186681Sed	nrow = r->tr_end.tp_row - r->tr_begin.tp_row;
161186681Sed	ncol = r->tr_end.tp_col - r->tr_begin.tp_col;
162186681Sed
163186681Sed	if (p->tp_row < r->tr_begin.tp_row) {
164186681Sed		/* Copy from top to bottom. */
165186681Sed		if (p->tp_col < r->tr_begin.tp_col) {
166186681Sed			/* Copy from left to right. */
167186681Sed			for (y = 0; y < nrow; y++) {
168186681Sed				d.tp_row = p->tp_row + y;
169186681Sed				for (x = 0; x < ncol; x++) {
170186681Sed					d.tp_col = p->tp_col + x;
171186681Sed					buffer[d.tp_col][d.tp_row] =
172186681Sed					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
173186681Sed					printchar(&d);
174186681Sed				}
175186681Sed			}
176186681Sed		} else {
177186681Sed			/* Copy from right to left. */
178186681Sed			for (y = 0; y < nrow; y++) {
179186681Sed				d.tp_row = p->tp_row + y;
180186681Sed				for (x = ncol - 1; x >= 0; x--) {
181186681Sed					d.tp_col = p->tp_col + x;
182186681Sed					buffer[d.tp_col][d.tp_row] =
183186681Sed					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
184186681Sed					printchar(&d);
185186681Sed				}
186186681Sed			}
187186681Sed		}
188186681Sed	} else {
189186681Sed		/* Copy from bottom to top. */
190186681Sed		if (p->tp_col < r->tr_begin.tp_col) {
191186681Sed			/* Copy from left to right. */
192186681Sed			for (y = nrow - 1; y >= 0; y--) {
193186681Sed				d.tp_row = p->tp_row + y;
194186681Sed				for (x = 0; x < ncol; x++) {
195186681Sed					d.tp_col = p->tp_col + x;
196186681Sed					buffer[d.tp_col][d.tp_row] =
197186681Sed					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
198186681Sed					printchar(&d);
199186681Sed				}
200186681Sed			}
201186681Sed		} else {
202186681Sed			/* Copy from right to left. */
203186681Sed			for (y = nrow - 1; y >= 0; y--) {
204186681Sed				d.tp_row = p->tp_row + y;
205186681Sed				for (x = ncol - 1; x >= 0; x--) {
206186681Sed					d.tp_col = p->tp_col + x;
207186681Sed					buffer[d.tp_col][d.tp_row] =
208186681Sed					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
209186681Sed					printchar(&d);
210186681Sed				}
211186681Sed			}
212186681Sed		}
213186681Sed	}
214186681Sed}
215186681Sed
216186681Sedstatic void
217186681Sedtest_param(void *s __unused, int cmd, int value)
218186681Sed{
219186681Sed
220186681Sed	switch (cmd) {
221186681Sed	case TP_SHOWCURSOR:
222186681Sed		curs_set(value);
223186681Sed		break;
224186681Sed	case TP_KEYPADAPP:
225186681Sed		keypad(stdscr, value ? TRUE : FALSE);
226186681Sed		break;
227186681Sed	}
228186681Sed}
229186681Sed
230186681Sedstatic void
231186681Sedtest_respond(void *s __unused, const void *buf, size_t len)
232186681Sed{
233186681Sed
234186681Sed	write(ptfd, buf, len);
235186681Sed}
236186681Sed
237186681Sedstatic void
238186681Sedredraw_border(void)
239186681Sed{
240186681Sed	unsigned int i;
241186681Sed
242186681Sed	for (i = 0; i < NROWS; i++)
243186681Sed		mvaddch(i, NCOLS, '|');
244186681Sed	for (i = 0; i < NCOLS; i++)
245186681Sed		mvaddch(NROWS, i, '-');
246186681Sed
247186681Sed	mvaddch(NROWS, NCOLS, '+');
248186681Sed}
249186681Sed
250186681Sedstatic void
251186681Sedredraw_all(void)
252186681Sed{
253186681Sed	teken_pos_t tp;
254186681Sed
255186681Sed	for (tp.tp_row = 0; tp.tp_row < NROWS; tp.tp_row++)
256186681Sed		for (tp.tp_col = 0; tp.tp_col < NCOLS; tp.tp_col++)
257186681Sed			printchar(&tp);
258186681Sed
259186681Sed	redraw_border();
260186681Sed}
261186681Sed
262186681Sedint
263186681Sedmain(int argc __unused, char *argv[] __unused)
264186681Sed{
265186681Sed	struct winsize ws;
266186681Sed	teken_t t;
267186681Sed	teken_pos_t tp;
268186681Sed	fd_set rfds;
269186681Sed	char b[256];
270186681Sed	ssize_t bl;
271186681Sed	const int ccolors[8] = { COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE };
272186681Sed	int i, j;
273186681Sed
274186681Sed	tp.tp_row = ws.ws_row = NROWS;
275186681Sed	tp.tp_col = ws.ws_col = NCOLS;
276186681Sed
277186681Sed	switch (forkpty(&ptfd, NULL, NULL, &ws)) {
278186681Sed	case -1:
279186681Sed		perror("forkpty");
280186681Sed		exit(1);
281186681Sed	case 0:
282186681Sed		setenv("TERM", "xterm-color", 1);
283186681Sed		setenv("LC_CTYPE", "UTF-8", 0);
284186681Sed		execlp("zsh", "-zsh", NULL);
285186681Sed		execlp("bash", "-bash", NULL);
286186681Sed		execlp("sh", "-sh", NULL);
287186681Sed		_exit(1);
288186681Sed	}
289186681Sed
290186681Sed	teken_init(&t, &tf, NULL);
291186681Sed	teken_set_winsize(&t, &tp);
292186681Sed
293186681Sed	initscr();
294186681Sed	raw();
295186681Sed	start_color();
296186681Sed	for (i = 0; i < 8; i++)
297186681Sed		for (j = 0; j < 8; j++)
298186681Sed			init_pair(i + 8 * j + 1, ccolors[i], ccolors[j]);
299186681Sed
300186681Sed	redraw_border();
301186681Sed
302186681Sed	FD_ZERO(&rfds);
303186681Sed
304186681Sed	for (;;) {
305186681Sed		FD_SET(STDIN_FILENO, &rfds);
306186681Sed		FD_SET(ptfd, &rfds);
307186681Sed
308186681Sed		if (select(ptfd + 1, &rfds, NULL, NULL, NULL) < 0) {
309186681Sed			if (errno == EINTR) {
310186681Sed				redraw_all();
311186681Sed				refresh();
312186681Sed				continue;
313186681Sed			}
314186681Sed			break;
315186681Sed		}
316186681Sed
317186681Sed		if (FD_ISSET(STDIN_FILENO, &rfds)) {
318186681Sed			bl = read(STDIN_FILENO, b, sizeof b);
319186681Sed			if (bl <= 0)
320186681Sed				break;
321186681Sed			write(ptfd, b, bl);
322186681Sed		}
323186681Sed
324186681Sed		if (FD_ISSET(ptfd, &rfds)) {
325186681Sed			bl = read(ptfd, b, sizeof b);
326186681Sed			if (bl <= 0)
327186681Sed				break;
328186681Sed			teken_input(&t, b, bl);
329186681Sed			refresh();
330186681Sed		}
331186681Sed	}
332186681Sed
333186681Sed	endwin();
334186681Sed
335186681Sed	return (0);
336186681Sed}
337