Changeset 1437


Ignore:
Timestamp:
Nov 27, 2006, 3:46:24 PM (17 years ago)
Author:
Sam Hocevar
Message:
  • Imported libcaca's test/term.c into our tree.
Location:
neercs/trunk
Files:
2 added
3 edited

Legend:

Unmodified
Added
Removed
  • neercs/trunk/configure.ac

    r1436 r1437  
    3232  AC_MSG_ERROR([you need libcaca version 0.99.beta10 or later])])
    3333
     34AC_CHECK_HEADERS(stdio.h pty.h)
     35
     36AC_CHECK_LIB(util, forkpty, UTIL_LIBS="${UTIL_LIBS} -lutil")
     37AC_SUBST(UTIL_LIBS)
     38
    3439# Optimizations
    3540CFLAGS="${CFLAGS} -g -O2 -fno-strength-reduce -fomit-frame-pointer"
  • neercs/trunk/src/Makefile.am

    r1436 r1437  
    22bin_PROGRAMS = neercs
    33
    4 neercs_SOURCES = main.c
     4neercs_SOURCES = main.c neercs.h term.c
    55neercs_CFLAGS = `pkg-config --cflags caca`
    66neercs_LDFLAGS = `pkg-config --libs caca`
     7neercs_LDADD = @UTIL_LIBS@
    78
  • neercs/trunk/src/main.c

    r1436 r1437  
    11/*
    2  *   $Id$
     2 *  neercs        console-based window manager
     3 *  Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
     4 *                All Rights Reserved
    35 *
    4  *   This program is free software; you can redistribute it and/or modify
    5  *   it under the terms of the GNU General Public License as published by
    6  *   the Free Software Foundation; either version 2 of the License, or
    7  *   (at your option) any later version.
     6 *  $Id$
    87 *
    9  *   This program is distributed in the hope that it will be useful,
    10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  *   GNU General Public License for more details.
    13  *
    14  *   You should have received a copy of the GNU General Public License
    15  *   along with this program; if not, write to the Free Software
    16  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     8 *  This program is free software; you can redistribute it and/or
     9 *  modify it under the terms of the Do What The Fuck You Want To
     10 *  Public License, Version 2, as published by Sam Hocevar. See
     11 *  http://sam.zoy.org/wtfpl/COPYING for more details.
    1712 */
    1813
    1914#include "config.h"
    2015
     16#include <stdio.h>
     17#include <string.h>
     18#include <stdlib.h>
     19#include <unistd.h>
     20#include <fcntl.h>
     21#include <sys/ioctl.h>
     22#if defined HAVE_PTY_H
     23#   include <pty.h>  /* for openpty and forkpty */
     24#else
     25#   include <util.h> /* for OS X */
     26#endif
     27#include <errno.h>
     28#include <cucul.h>
    2129#include <caca.h>
    2230
    23 int main (int argc, char **argv)
     31#include "neercs.h"
     32
     33#define XTAB 5
     34#define YTAB 3
     35
     36static int create_pty(char *cmd, unsigned int w, unsigned int h);
     37static int set_tty_size(int fd, unsigned int w, unsigned int h);
     38
     39int main(int argc, char **argv)
    2440{
     41    static cucul_canvas_t *cv;
     42    static caca_display_t *dp;
     43    static struct screen *screen;
     44    int pty = 0, prevpty = 0, i, n, w, h, eof = 0, refresh = 1, command = 0;
     45
     46    if(argc < 2)
     47    {
     48        fprintf(stderr, "usage: %s <cmd1> [<cmd2> [<cmd3> ...]]\n", argv[0]);
     49        fprintf(stderr, "eg. \"%s zsh bash\"\n", argv[0]);
     50        return 1;
     51    }
     52
     53    cv = cucul_create_canvas(0, 0);
     54    dp = caca_create_display(cv);
     55    if(!dp)
     56        return 1;
     57
     58    n = argc - 1;
     59    screen = malloc(n * sizeof(struct screen));
     60
     61    w = cucul_get_canvas_width(cv);
     62    h = cucul_get_canvas_height(cv);
     63
     64    w = w <= XTAB * n ? 1 : w - XTAB * (n - 1) - 2;
     65    h = h <= YTAB * n ? 1 : h - YTAB * (n - 1) - 2;
     66
     67    for(i = 0; i < n; i++)
     68    {
     69        screen[i].cv = cucul_create_canvas(w, h);
     70        screen[i].init = 0;
     71    }
     72
     73    cucul_set_color_ansi(cv, CUCUL_LIGHTRED, CUCUL_BLACK);
     74    cucul_draw_cp437_box(cv, (n - 1 - pty) * XTAB, pty * YTAB,
     75                         w + (n - 1 - pty) * XTAB + 1, h + pty * YTAB + 1);
     76
     77    caca_refresh_display(dp);
     78
     79    for(i = 0; i < n; i++)
     80    {
     81        screen[i].buf = NULL;
     82        screen[i].total = 0;
     83        screen[i].fd = create_pty(argv[i + 1], w, h);
     84        if(screen[i].fd < 0)
     85            return -1;
     86    }
     87
     88    for(;;)
     89    {
     90        struct timeval tv;
     91        fd_set fdset;
     92        caca_event_t ev;
     93        int maxfd = 0, ret;
     94
     95        /* Read data, if any */
     96        FD_ZERO(&fdset);
     97        for(i = 0; i < n; i++)
     98        {
     99            FD_SET(screen[i].fd, &fdset);
     100            if(screen[i].fd > maxfd)
     101                maxfd = screen[i].fd;
     102        }
     103        tv.tv_sec = 0;
     104        tv.tv_usec = 50000;
     105        ret = select(maxfd + 1, &fdset, NULL, NULL, &tv);
     106
     107        if(ret < 0)
     108        {
     109            if(errno == EINTR)
     110                ; /* We probably got a SIGWINCH, ignore it */
     111            else
     112            {
     113                for(i = 0; i < n; i++)
     114                    if(screen[i].total)
     115                        break;
     116                if(i == n)
     117                    break;
     118            }
     119        }
     120        else if(ret) for(i = 0; i < n; i++)
     121        {
     122            /* FIXME: try a new strategy: read all filedescriptors until
     123             * each of them starved at least once. */
     124
     125            if(!FD_ISSET(screen[i].fd, &fdset))
     126                continue;
     127
     128            for(;;)
     129            {
     130                ssize_t nr;
     131
     132                screen[i].buf = realloc(screen[i].buf, screen[i].total + 1024);
     133                nr = read(screen[i].fd, screen[i].buf + screen[i].total, 1024);
     134
     135                if(nr > 0)
     136                {
     137                    screen[i].total += nr;
     138                    continue;
     139                }
     140
     141                if(nr == 0 || errno != EWOULDBLOCK)
     142                    eof = 1;
     143
     144                break;
     145            }
     146        }
     147
     148        for(i = 0; i < n; i++) if(screen[i].total)
     149        {
     150            unsigned long int bytes;
     151
     152            bytes = import_term(&screen[i], screen[i].buf, screen[i].total);
     153
     154            if(bytes > 0)
     155            {
     156                screen[i].total -= bytes;
     157                memmove(screen[i].buf, screen[i].buf + bytes, screen[i].total);
     158                refresh = 1;
     159            }
     160        }
     161
     162        /* Get events, if any */
     163        ret = caca_get_event(dp, CACA_EVENT_ANY, &ev, 0);
     164        if(ret && (ev.type & CACA_EVENT_KEY_PRESS))
     165        {
     166            if(command)
     167            {
     168                command = 0;
     169
     170                switch(ev.data.key.ch)
     171                {
     172                case 0x01: //CACA_KEY_CTRL_A:
     173                    pty ^= prevpty;
     174                    prevpty ^= pty;
     175                    pty ^= prevpty;
     176                    refresh = 1;
     177                    break;
     178                case 'n':
     179                case ' ':
     180                case '\0':
     181                case 0x0e: //CACA_KEY_CTRL_N:
     182                    prevpty = pty;
     183                    pty = (pty + 1) % n;
     184                    refresh = 1;
     185                    break;
     186                case 'p':
     187                case 0x10: //CACA_KEY_CTRL_P:
     188                    prevpty = pty;
     189                    pty = (pty + n - 1) % n;
     190                    refresh = 1;
     191                    break;
     192                }
     193            }
     194            else
     195            {
     196                switch(ev.data.key.ch)
     197                {
     198                case 0x01: //CACA_KEY_CTRL_A:
     199                    command = 1; break;
     200                case CACA_KEY_UP:
     201                    write(screen[pty].fd, "\x1b[A", 3); break;
     202                case CACA_KEY_DOWN:
     203                    write(screen[pty].fd, "\x1b[B", 3); break;
     204                case CACA_KEY_RIGHT:
     205                    write(screen[pty].fd, "\x1b[C", 3); break;
     206                case CACA_KEY_LEFT:
     207                    write(screen[pty].fd, "\x1b[D", 3); break;
     208                default:
     209                    write(screen[pty].fd, &ev.data.key.ch, 1); break;
     210                }
     211            }
     212        }
     213        else if(ret && (ev.type & CACA_EVENT_RESIZE))
     214        {
     215            w = cucul_get_canvas_width(cv);
     216            h = cucul_get_canvas_height(cv);
     217            w = w <= XTAB * n ? 1 : w - XTAB * (n - 1) - 2;
     218            h = h <= YTAB * n ? 1 : h - YTAB * (n - 1) - 2;
     219            for(i = 0; i < n; i++)
     220            {
     221                cucul_set_canvas_size(screen[i].cv, w, h);
     222                set_tty_size(screen[i].fd, w, h);
     223            }
     224            cucul_clear_canvas(cv);
     225            refresh = 1;
     226        }
     227
     228        /* Refresh screen */
     229        if(refresh)
     230        {
     231            refresh = 0;
     232
     233            for(i = 0; i < n; i++)
     234            {
     235                int j = (pty + n - 1 - i) % n;
     236                cucul_blit(cv, (n - 1 - j) * XTAB + 1,
     237                               j * YTAB + 1, screen[j].cv, NULL);
     238                cucul_draw_cp437_box(cv, (n - 1 - j) * XTAB, j * YTAB,
     239                                     w + (n - 1 - j) * XTAB + 1, h + j * YTAB + 1);
     240            }
     241            caca_refresh_display(dp);
     242        }
     243
     244        if(eof)
     245        {
     246            for(i = 0; i < n; i++)
     247                if(screen[i].total)
     248                    break;
     249            if(i == n)
     250                break;
     251        }
     252    }
     253
     254    caca_get_event(dp, CACA_EVENT_KEY_PRESS, NULL, -1);
     255
     256    /* Clean up */
     257    caca_free_display(dp);
     258    cucul_free_canvas(cv);
     259    for(i = 0; i < n; i++)
     260        cucul_free_canvas(screen[i].cv);
     261
    25262    return 0;
    26263}
    27264
     265static int create_pty(char *cmd, unsigned int w, unsigned int h)
     266{
     267    char **argv;
     268    int fd;
     269    pid_t pid;
     270
     271    pid = forkpty(&fd, NULL, NULL, NULL);
     272    if(pid < 0)
     273    {
     274        fprintf(stderr, "forkpty() error\n");
     275        return -1;
     276    }
     277    else if(pid == 0)
     278    {
     279        set_tty_size(0, w, h);
     280        putenv("CACA_DRIVER=slang");
     281        putenv("TERM=xterm");
     282        argv = malloc(2 * sizeof(char *));
     283        argv[0] = cmd;
     284        argv[1] = NULL;
     285        execvp(cmd, argv);
     286        fprintf(stderr, "execvp() error\n");
     287        return -1;
     288    }
     289
     290    fcntl(fd, F_SETFL, O_NDELAY);
     291    return fd;
     292#if 0
     293    fprintf(stderr, "forkpty() not available\n");
     294    return -1;
     295#endif
     296}
     297
     298static int set_tty_size(int fd, unsigned int w, unsigned int h)
     299{
     300    struct winsize ws;
     301
     302    memset(&ws, 0, sizeof(ws));
     303    ws.ws_row = h;
     304    ws.ws_col = w;
     305    ioctl(fd, TIOCSWINSZ, (char *)&ws);
     306
     307    return 0;
     308}
     309
Note: See TracChangeset for help on using the changeset viewer.