瀏覽代碼

* A few improvements to the screen/splitvt clone project.

tags/v0.99.beta14
Sam Hocevar sam 19 年之前
父節點
當前提交
9df4f8a821
共有 1 個檔案被更改,包括 174 行新增80 行删除
  1. +174
    -80
      test/term.c

+ 174
- 80
test/term.c 查看文件

@@ -20,150 +20,230 @@
# include <stdlib.h> # include <stdlib.h>
# include <unistd.h> # include <unistd.h>
# include <fcntl.h> # include <fcntl.h>
# include <sys/ioctl.h>
# if defined HAVE_PTY_H # if defined HAVE_PTY_H
# include <pty.h> /* for openpty and forkpty */ # include <pty.h> /* for openpty and forkpty */
# else
# include <util.h> /* for OS X */
# endif # endif
#endif #endif


#include "cucul.h" #include "cucul.h"
#include "caca.h" #include "caca.h"


static int run_in_pty(char *cmd);
#define XTAB 3
#define YTAB 2

struct screen
{
cucul_canvas_t *cv;
int fd;
unsigned char *buf;
long int total;
int w, h;
};

static int create_pty(char *cmd, unsigned int w, unsigned int h);
static int set_tty_size(int fd, unsigned int w, unsigned int h);


int main(int argc, char **argv) int main(int argc, char **argv)
{ {
static cucul_canvas_t *cv, *app[2];
static cucul_canvas_t *cv;
static caca_display_t *dp; static caca_display_t *dp;
unsigned char *buf[2];
long int total[2];
int ptyfd[2], pty = 0;
int w, h, eof = 0;
static struct screen *screen;
int pty = 0, prevpty = 0, i, n, w, h, eof = 0, refresh = 1, command = 0;


if(argc < 3)
if(argc < 2)
{ {
fprintf(stderr, "usage: %s <cmd1> <cmd2>\n", argv[0]);
fprintf(stderr, "eg. \"%s bash bash\"\n", argv[0]);
fprintf(stderr, "usage: %s <cmd1> [<cmd2> [<cmd3> ...]]\n", argv[0]);
fprintf(stderr, "eg. \"%s zsh bash\"\n", argv[0]);
return 1; return 1;
} }


cv = cucul_create_canvas(80 + 7, 24 + 7);
cv = cucul_create_canvas(0, 0);
dp = caca_create_display(cv); dp = caca_create_display(cv);
if(!dp) if(!dp)
return 1; return 1;


// w = cucul_get_canvas_width(cv) - 7;
// h = cucul_get_canvas_height(cv) - 7;
w = 80; h = 24;
n = argc - 1;
screen = malloc(n * sizeof(struct screen));


if(w < 0 || h < 0)
return 1;
w = cucul_get_canvas_width(cv);
h = cucul_get_canvas_height(cv);

w = w <= XTAB * n ? 1 : w - XTAB * n;
h = h <= YTAB * n ? 1 : h - YTAB * n;


app[0] = cucul_create_canvas(w, h);
app[1] = cucul_create_canvas(w, h);
for(i = 0; i < n; i++)
screen[i].cv = cucul_create_canvas(w, h);


cucul_set_color_ansi(cv, CUCUL_LIGHTRED, CUCUL_BLACK); cucul_set_color_ansi(cv, CUCUL_LIGHTRED, CUCUL_BLACK);
cucul_draw_thin_box(cv, pty * 5, pty * 5,
80 + pty * 5 + 1, 24 + pty * 5 + 1);
cucul_draw_cp437_box(cv, (n - 1 - pty) * XTAB, pty * YTAB,
w + (n - 1 - pty) * XTAB + 1, h + pty * YTAB + 1);


caca_refresh_display(dp); caca_refresh_display(dp);


buf[0] = buf[1] = NULL;
total[0] = total[1] = 0;

ptyfd[0] = run_in_pty(argv[1]);
ptyfd[1] = run_in_pty(argv[2]);

if(ptyfd[0] < 0 || ptyfd[1] < 0)
return -1;

fcntl(ptyfd[0], F_SETFL, O_NDELAY);
fcntl(ptyfd[1], F_SETFL, O_NDELAY);
for(i = 0; i < n; i++)
{
screen[i].buf = NULL;
screen[i].total = 0;
screen[i].fd = create_pty(argv[i + 1], w, h);
if(screen[i].fd < 0)
return -1;
}


for(;;) for(;;)
{ {
struct timeval tv; struct timeval tv;
fd_set fdset; fd_set fdset;
caca_event_t ev; caca_event_t ev;
int i, ret, refresh = 0;

ret = caca_get_event(dp, CACA_EVENT_ANY, &ev, 0);
if(ret && ev.type & CACA_EVENT_KEY_PRESS)
{
switch(ev.data.key.ch)
{
case CACA_KEY_CTRL_A:
cucul_draw_box(cv, pty * 5, pty * 5,
80 + pty * 5 + 1, 24 + pty * 5 + 1, ' ');
pty = 1 - pty;
refresh = 1;
break;
case CACA_KEY_UP:
write(ptyfd[pty], "\x1b[A", 3); break;
case CACA_KEY_DOWN:
write(ptyfd[pty], "\x1b[B", 3); break;
case CACA_KEY_RIGHT:
write(ptyfd[pty], "\x1b[C", 3); break;
case CACA_KEY_LEFT:
write(ptyfd[pty], "\x1b[D", 3); break;
default:
write(ptyfd[pty], &ev.data.key.ch, 1); break;
}
}
int i, maxfd = 0, ret;


/* Read data, if any */ /* Read data, if any */
FD_ZERO(&fdset); FD_ZERO(&fdset);
FD_SET(ptyfd[0], &fdset);
FD_SET(ptyfd[1], &fdset);
for(i = 0; i < n; i++)
{
FD_SET(screen[i].fd, &fdset);
if(screen[i].fd > maxfd)
maxfd = screen[i].fd;
}
tv.tv_sec = 0; tv.tv_sec = 0;
tv.tv_usec = 50000; tv.tv_usec = 50000;
ret = select(ptyfd[0] + ptyfd[1] + 1, &fdset, NULL, NULL, &tv);
ret = select(maxfd + 1, &fdset, NULL, NULL, &tv);


if(ret < 0) if(ret < 0)
{ {
if(!total[0] && !total[1])
break;
if(errno == EINTR)
; /* We probably got a SIGWINCH, ignore it */
else
{
for(i = 0; i < n; i++)
if(screen[i].total)
break;
if(i == n)
break;
}
} }
else if(ret) for(i = 0; i < 2; i++)
else if(ret) for(i = 0; i < n; i++)
{ {
if(FD_ISSET(ptyfd[i], &fdset))
if(FD_ISSET(screen[i].fd, &fdset))
{ {
ssize_t n; ssize_t n;


buf[i] = realloc(buf[i], total[i] + 4096);
n = read(ptyfd[i], buf[i] + total[i], 4096);
screen[i].buf = realloc(screen[i].buf, screen[i].total + 4096);
n = read(screen[i].fd, screen[i].buf + screen[i].total, 4096);


if(n > 0) if(n > 0)
total[i] += n;
screen[i].total += n;
else if(n == 0 || errno != EWOULDBLOCK) else if(n == 0 || errno != EWOULDBLOCK)
eof = 1; eof = 1;
} }
} }


for(i = 0; i < 2; i++) if(total[i])
for(i = 0; i < n; i++) if(screen[i].total)
{ {
unsigned long int bytes; unsigned long int bytes;


bytes = cucul_import_memory(app[i], buf[i], total[i], "utf8");
bytes = cucul_import_memory(screen[i].cv, screen[i].buf, screen[i].total, "utf8");


if(bytes > 0) if(bytes > 0)
{ {
total[i] -= bytes;
memmove(buf[i], buf[i] + bytes, total[i]);
screen[i].total -= bytes;
memmove(screen[i].buf, screen[i].buf + bytes, screen[i].total);
refresh = 1; refresh = 1;
} }
} }


/* Get events, if any */
ret = caca_get_event(dp, CACA_EVENT_ANY, &ev, 0);
if(ret && (ev.type & CACA_EVENT_KEY_PRESS))
{
if(command)
{
command = 0;

switch(ev.data.key.ch)
{
case CACA_KEY_CTRL_A:
pty ^= prevpty;
prevpty ^= pty;
pty ^= prevpty;
refresh = 1;
break;
case 'n':
case ' ':
case '\0':
case CACA_KEY_CTRL_N:
prevpty = pty;
pty = (pty + 1) % n;
refresh = 1;
break;
case 'p':
case CACA_KEY_CTRL_P:
prevpty = pty;
pty = (pty + n - 1) % n;
refresh = 1;
break;
}
}
else
{
switch(ev.data.key.ch)
{
case CACA_KEY_CTRL_A:
command = 1; break;
case CACA_KEY_UP:
write(screen[pty].fd, "\x1b[A", 3); break;
case CACA_KEY_DOWN:
write(screen[pty].fd, "\x1b[B", 3); break;
case CACA_KEY_RIGHT:
write(screen[pty].fd, "\x1b[C", 3); break;
case CACA_KEY_LEFT:
write(screen[pty].fd, "\x1b[D", 3); break;
default:
write(screen[pty].fd, &ev.data.key.ch, 1); break;
}
}
}
else if(ret && (ev.type & CACA_EVENT_RESIZE))
{
w = cucul_get_canvas_width(cv);
h = cucul_get_canvas_height(cv);
w = w <= XTAB * n ? 1 : w - XTAB * n;
h = h <= YTAB * n ? 1 : h - YTAB * n;
for(i = 0; i < n; i++)
{
cucul_set_canvas_size(screen[i].cv, w, h);
set_tty_size(screen[i].fd, w, h);
}
cucul_clear_canvas(cv);
refresh = 1;
}

/* Refresh screen */
if(refresh) if(refresh)
{ {
cucul_blit(cv, 5 * !pty + 1, 5 * !pty + 1, app[!pty], NULL);
cucul_blit(cv, 5 * pty + 1, 5 * pty + 1, app[pty], NULL);
cucul_draw_thin_box(cv, pty * 5, pty * 5,
80 + pty * 5 + 1, 24 + pty * 5 + 1);
refresh = 0;

for(i = 0; i < n; i++)
{
int j = (pty + n - 1 - i) % n;
cucul_blit(cv, (n - 1 - j) * XTAB + 1,
j * YTAB + 1, screen[j].cv, NULL);
cucul_draw_cp437_box(cv, (n - 1 - j) * XTAB, j * YTAB,
w + (n - 1 - j) * XTAB + 1, h + j * YTAB + 1);
}
caca_refresh_display(dp); caca_refresh_display(dp);
} }


if(eof && !total[0] && !total[1])
break;
if(eof)
{
for(i = 0; i < n; i++)
if(screen[i].total)
break;
if(i == n)
break;
}
} }


caca_get_event(dp, CACA_EVENT_KEY_PRESS, NULL, -1); caca_get_event(dp, CACA_EVENT_KEY_PRESS, NULL, -1);
@@ -171,15 +251,14 @@ int main(int argc, char **argv)
/* Clean up */ /* Clean up */
caca_free_display(dp); caca_free_display(dp);
cucul_free_canvas(cv); cucul_free_canvas(cv);
cucul_free_canvas(app[0]);
cucul_free_canvas(app[1]);
for(i = 0; i < n; i++)
cucul_free_canvas(screen[i].cv);


return 0; return 0;
} }


static int run_in_pty(char *cmd)
static int create_pty(char *cmd, unsigned int w, unsigned int h)
{ {
#if defined HAVE_PTY_H
char **argv; char **argv;
int fd; int fd;
pid_t pid; pid_t pid;
@@ -192,7 +271,9 @@ static int run_in_pty(char *cmd)
} }
else if(pid == 0) else if(pid == 0)
{ {
set_tty_size(0, w, h);
putenv("CACA_DRIVER=slang"); putenv("CACA_DRIVER=slang");
putenv("TERM=xterm");
argv = malloc(2 * sizeof(char *)); argv = malloc(2 * sizeof(char *));
argv[0] = cmd; argv[0] = cmd;
argv[1] = NULL; argv[1] = NULL;
@@ -201,10 +282,23 @@ static int run_in_pty(char *cmd)
return -1; return -1;
} }


fcntl(fd, F_SETFL, O_NDELAY);
return fd; return fd;
#else
#if 0
fprintf(stderr, "forkpty() not available\n"); fprintf(stderr, "forkpty() not available\n");
return -1; return -1;
#endif #endif
} }


static int set_tty_size(int fd, unsigned int w, unsigned int h)
{
struct winsize ws;

memset(&ws, 0, sizeof(ws));
ws.ws_row = h;
ws.ws_col = w;
ioctl(fd, TIOCSWINSZ, (char *)&ws);

return 0;
}


Loading…
取消
儲存