source: neercs/trunk/src/main.c @ 1437

Last change on this file since 1437 was 1437, checked in by Sam Hocevar, 14 years ago
  • Imported libcaca's test/term.c into our tree.
  • Property svn:keywords set to Id
File size: 8.0 KB
Line 
1/*
2 *  neercs        console-based window manager
3 *  Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: main.c 1437 2006-11-27 14:46:24Z sam $
7 *
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.
12 */
13
14#include "config.h"
15
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>
29#include <caca.h>
30
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)
40{
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
262    return 0;
263}
264
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 TracBrowser for help on using the repository browser.