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

Last change on this file since 1834 was 1834, checked in by Sam Hocevar, 16 years ago
  • Display miniatures from all other windows at the bottom of the screen.
  • Property svn:keywords set to Id
File size: 10.1 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 1834 2007-09-30 17:12:21Z sam $
7 *
8 *  This program is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15#include "config.h"
16
17#include <stdio.h>
18#include <string.h>
19#include <stdlib.h>
20#include <unistd.h>
21#include <fcntl.h>
22#include <sys/ioctl.h>
23#if defined HAVE_PTY_H
24#   include <pty.h>  /* for openpty and forkpty */
25#else
26#   include <util.h> /* for OS X */
27#endif
28#include <errno.h>
29#include <cucul.h>
30#include <caca.h>
31
32#include "neercs.h"
33
34#define XTAB 5
35#define YTAB 3
36
37static int create_pty(char *cmd, unsigned int w, unsigned int h);
38static int set_tty_size(int fd, unsigned int w, unsigned int h);
39
40int main(int argc, char **argv)
41{
42    static cucul_canvas_t *cv;
43    static caca_display_t *dp;
44    static struct screen *screen;
45    int pty = 0, prevpty = 0, i, n, w, h;
46    int eof = 0, refresh = 1, command = 0, mini = 1;
47
48    if(argc < 2)
49    {
50        fprintf(stderr, "usage: %s <cmd1> [<cmd2> [<cmd3> ...]]\n", argv[0]);
51        fprintf(stderr, "eg. \"%s zsh bash\"\n", argv[0]);
52        return 1;
53    }
54
55    cv = cucul_create_canvas(0, 0);
56    dp = caca_create_display(cv);
57    if(!dp)
58        return 1;
59
60    n = argc - 1;
61    screen = malloc(n * sizeof(struct screen));
62
63    w = cucul_get_canvas_width(cv);
64    h = cucul_get_canvas_height(cv);
65
66    w = w <= XTAB * n ? 1 : w - XTAB * (n - 1) - 2;
67    h = h <= YTAB * n ? 1 : h - YTAB * (n - 1) - 2 - 6;
68
69    for(i = 0; i < n; i++)
70    {
71        screen[i].cv = cucul_create_canvas(w, h);
72        screen[i].init = 0;
73    }
74
75    cucul_set_color_ansi(cv, CUCUL_LIGHTRED, CUCUL_BLACK);
76    cucul_draw_cp437_box(cv, (n - 1 - pty) * XTAB, pty * YTAB,
77                         w + (n - 1 - pty) * XTAB + 1, h + pty * YTAB + 1);
78
79    caca_refresh_display(dp);
80
81    for(i = 0; i < n; i++)
82    {
83        screen[i].buf = NULL;
84        screen[i].total = 0;
85        screen[i].fd = create_pty(argv[i + 1], w, h);
86        if(screen[i].fd < 0)
87            return -1;
88    }
89
90    for(;;)
91    {
92        struct timeval tv;
93        fd_set fdset;
94        caca_event_t ev;
95        int maxfd = 0, ret;
96
97        /* Read data, if any */
98        FD_ZERO(&fdset);
99        for(i = 0; i < n; i++)
100        {
101            FD_SET(screen[i].fd, &fdset);
102            if(screen[i].fd > maxfd)
103                maxfd = screen[i].fd;
104        }
105        tv.tv_sec = 0;
106        tv.tv_usec = 50000;
107        ret = select(maxfd + 1, &fdset, NULL, NULL, &tv);
108
109        if(ret < 0)
110        {
111            if(errno == EINTR)
112                ; /* We probably got a SIGWINCH, ignore it */
113            else
114            {
115                for(i = 0; i < n; i++)
116                    if(screen[i].total)
117                        break;
118                if(i == n)
119                    break;
120            }
121        }
122        else if(ret) for(i = 0; i < n; i++)
123        {
124            /* FIXME: try a new strategy: read all filedescriptors until
125             * each of them starved at least once. */
126
127            if(!FD_ISSET(screen[i].fd, &fdset))
128                continue;
129
130            for(;;)
131            {
132                ssize_t nr;
133
134                screen[i].buf = realloc(screen[i].buf, screen[i].total + 1024);
135                nr = read(screen[i].fd, screen[i].buf + screen[i].total, 1024);
136
137                if(nr > 0)
138                {
139                    screen[i].total += nr;
140                    continue;
141                }
142
143                if(nr == 0 || errno != EWOULDBLOCK)
144                    eof = 1;
145
146                break;
147            }
148        }
149
150        for(i = 0; i < n; i++) if(screen[i].total)
151        {
152            unsigned long int bytes;
153
154            bytes = import_term(&screen[i], screen[i].buf, screen[i].total);
155
156            if(bytes > 0)
157            {
158                screen[i].total -= bytes;
159                memmove(screen[i].buf, screen[i].buf + bytes, screen[i].total);
160                refresh = 1;
161            }
162        }
163
164        /* Get events, if any */
165        ret = caca_get_event(dp, CACA_EVENT_ANY, &ev, 0);
166        if(ret && (ev.type & CACA_EVENT_KEY_PRESS))
167        {
168            if(command)
169            {
170                command = 0;
171
172                switch(ev.data.key.ch)
173                {
174                case 0x01: //CACA_KEY_CTRL_A:
175                    pty ^= prevpty;
176                    prevpty ^= pty;
177                    pty ^= prevpty;
178                    refresh = 1;
179                    break;
180                case 'm':
181                case 0x0d: //CACA_KEY_CTRL_M:
182                    mini = !mini;
183                    refresh = 1;
184                    break;
185                case 'n':
186                case ' ':
187                case '\0':
188                case 0x0e: //CACA_KEY_CTRL_N:
189                    prevpty = pty;
190                    pty = (pty + 1) % n;
191                    refresh = 1;
192                    break;
193                case 'p':
194                case 0x10: //CACA_KEY_CTRL_P:
195                    prevpty = pty;
196                    pty = (pty + n - 1) % n;
197                    refresh = 1;
198                    break;
199                }
200            }
201            else
202            {
203                switch(ev.data.key.ch)
204                {
205                case 0x01: //CACA_KEY_CTRL_A:
206                    command = 1; break;
207                case CACA_KEY_UP:
208                    write(screen[pty].fd, "\x1b[A", 3); break;
209                case CACA_KEY_DOWN:
210                    write(screen[pty].fd, "\x1b[B", 3); break;
211                case CACA_KEY_RIGHT:
212                    write(screen[pty].fd, "\x1b[C", 3); break;
213                case CACA_KEY_LEFT:
214                    write(screen[pty].fd, "\x1b[D", 3); break;
215                default:
216                    write(screen[pty].fd, &ev.data.key.ch, 1); break;
217                }
218            }
219        }
220        else if(ret && (ev.type & CACA_EVENT_RESIZE))
221        {
222            w = cucul_get_canvas_width(cv);
223            h = cucul_get_canvas_height(cv);
224            w = w <= XTAB * n ? 1 : w - XTAB * (n - 1) - 2;
225            h = h <= YTAB * n ? 1 : h - YTAB * (n - 1) - 2;
226            for(i = 0; i < n; i++)
227            {
228                cucul_set_canvas_size(screen[i].cv, w, h);
229                set_tty_size(screen[i].fd, w, h);
230            }
231            cucul_clear_canvas(cv);
232            refresh = 1;
233        }
234
235        /* Refresh screen */
236        if(refresh)
237        {
238            refresh = 0;
239
240            cucul_set_color_ansi(cv, CUCUL_LIGHTRED, CUCUL_BLACK);
241
242            for(i = 0; i < n; i++)
243            {
244                int j = (pty + n - 1 - i) % n;
245                cucul_blit(cv, (n - 1 - j) * XTAB + 1,
246                               j * YTAB + 1, screen[j].cv, NULL);
247                cucul_draw_cp437_box(cv, (n - 1 - j) * XTAB, j * YTAB,
248                                     w + (n - 1 - j) * XTAB + 1, h + j * YTAB + 1);
249            }
250
251            if(mini)
252            {
253                char const * const *fonts;
254                cucul_dither_t *d;
255                cucul_font_t *f;
256                uint8_t *buf;
257                int miniw, minih;
258
259                fonts = cucul_get_font_list();
260                f = cucul_load_font(fonts[0], 0);
261
262                miniw = cucul_get_canvas_width(screen[0].cv)
263                         * cucul_get_font_width(f);
264                minih = cucul_get_canvas_height(screen[0].cv)
265                         * cucul_get_font_height(f);
266                buf = malloc(4 * miniw * minih);
267
268#if defined(HAVE_ENDIAN_H)
269                if(__BYTE_ORDER == __BIG_ENDIAN)
270#else
271                /* This is compile-time optimised with at least -O1 or -Os */
272                uint32_t const tmp = 0x12345678;
273                if(*(uint8_t const *)&tmp == 0x12)
274#endif
275                    d = cucul_create_dither(32, miniw, minih, 4 * miniw,
276                                            0xff0000, 0xff00, 0xff, 0x0);
277                else
278                    d = cucul_create_dither(32, miniw, minih, 4 * miniw,
279                                            0xff00, 0xff0000, 0xff000000, 0x0);
280
281                for(i = 0; i < n; i++)
282                {
283                    cucul_render_canvas(screen[i].cv, f, buf,
284                                        miniw, minih, miniw * 4);
285                    cucul_dither_bitmap(cv, 20 * i,
286                              cucul_get_canvas_height(cv) - 6, 19, 6, d, buf);
287                    cucul_set_color_ansi(cv, CUCUL_WHITE, CUCUL_BLUE);
288                    cucul_printf(cv, 20 * i,
289                                 cucul_get_canvas_height(cv) - 6, "(%i)", i);
290                }
291
292                cucul_free_dither(d);
293                cucul_free_font(f);
294
295                free(buf);
296            }
297
298            caca_refresh_display(dp);
299        }
300
301        if(eof)
302        {
303            for(i = 0; i < n; i++)
304                if(screen[i].total)
305                    break;
306            if(i == n)
307                break;
308        }
309    }
310
311    caca_get_event(dp, CACA_EVENT_KEY_PRESS, NULL, -1);
312
313    /* Clean up */
314    caca_free_display(dp);
315    cucul_free_canvas(cv);
316    for(i = 0; i < n; i++)
317        cucul_free_canvas(screen[i].cv);
318
319    return 0;
320}
321
322static int create_pty(char *cmd, unsigned int w, unsigned int h)
323{
324    char **argv;
325    int fd;
326    pid_t pid;
327
328    pid = forkpty(&fd, NULL, NULL, NULL);
329    if(pid < 0)
330    {
331        fprintf(stderr, "forkpty() error\n");
332        return -1;
333    }
334    else if(pid == 0)
335    {
336        set_tty_size(0, w, h);
337        putenv("CACA_DRIVER=slang");
338        putenv("TERM=xterm");
339        argv = malloc(2 * sizeof(char *));
340        argv[0] = cmd;
341        argv[1] = NULL;
342        execvp(cmd, argv);
343        fprintf(stderr, "execvp() error\n");
344        return -1;
345    }
346
347    fcntl(fd, F_SETFL, O_NDELAY);
348    return fd;
349#if 0
350    fprintf(stderr, "forkpty() not available\n");
351    return -1;
352#endif
353}
354
355static int set_tty_size(int fd, unsigned int w, unsigned int h)
356{
357    struct winsize ws;
358
359    memset(&ws, 0, sizeof(ws));
360    ws.ws_row = h;
361    ws.ws_col = w;
362    ioctl(fd, TIOCSWINSZ, (char *)&ws);
363
364    return 0;
365}
366
Note: See TracBrowser for help on using the repository browser.