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