2012-06-17 09:28:02 -07:00
|
|
|
#include "private.h"
|
2012-06-12 03:10:01 -07:00
|
|
|
#include <Elementary.h>
|
|
|
|
#include "termpty.h"
|
2012-07-13 01:46:33 -07:00
|
|
|
#include "termptyesc.h"
|
|
|
|
#include "termptyops.h"
|
2012-06-12 03:10:01 -07:00
|
|
|
#include <sys/types.h>
|
2012-08-05 18:13:20 -07:00
|
|
|
#include <signal.h>
|
|
|
|
#include <sys/wait.h>
|
2012-06-12 03:10:01 -07:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/ioctl.h>
|
2012-06-19 12:40:40 -07:00
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
2012-06-12 03:10:01 -07:00
|
|
|
|
2012-06-19 12:53:02 -07:00
|
|
|
/* specific log domain to help debug only terminal code parser */
|
2012-07-13 01:46:33 -07:00
|
|
|
int _termpty_log_dom = -1;
|
2012-06-19 12:53:02 -07:00
|
|
|
|
|
|
|
#undef CRITICAL
|
|
|
|
#undef ERR
|
|
|
|
#undef WRN
|
|
|
|
#undef INF
|
|
|
|
#undef DBG
|
|
|
|
|
|
|
|
#define CRITICAL(...) EINA_LOG_DOM_CRIT(_termpty_log_dom, __VA_ARGS__)
|
|
|
|
#define ERR(...) EINA_LOG_DOM_ERR(_termpty_log_dom, __VA_ARGS__)
|
|
|
|
#define WRN(...) EINA_LOG_DOM_WARN(_termpty_log_dom, __VA_ARGS__)
|
|
|
|
#define INF(...) EINA_LOG_DOM_INFO(_termpty_log_dom, __VA_ARGS__)
|
|
|
|
#define DBG(...) EINA_LOG_DOM_DBG(_termpty_log_dom, __VA_ARGS__)
|
|
|
|
|
|
|
|
void
|
|
|
|
termpty_init(void)
|
|
|
|
{
|
|
|
|
if (_termpty_log_dom >= 0) return;
|
|
|
|
|
|
|
|
_termpty_log_dom = eina_log_domain_register("termpty", NULL);
|
|
|
|
if (_termpty_log_dom < 0)
|
|
|
|
EINA_LOG_CRIT("could not create log domain 'termpty'.");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
termpty_shutdown(void)
|
|
|
|
{
|
|
|
|
if (_termpty_log_dom < 0) return;
|
|
|
|
eina_log_domain_unregister(_termpty_log_dom);
|
|
|
|
_termpty_log_dom = -1;
|
|
|
|
}
|
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
static void
|
2012-06-30 17:24:30 -07:00
|
|
|
_handle_buf(Termpty *ty, const Eina_Unicode *codepoints, int len)
|
2012-06-12 03:10:01 -07:00
|
|
|
{
|
2012-06-30 17:24:30 -07:00
|
|
|
Eina_Unicode *c, *ce, *b;
|
|
|
|
int n, bytes;
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2012-06-25 18:38:13 -07:00
|
|
|
c = (int *)codepoints;
|
2012-06-12 03:10:01 -07:00
|
|
|
ce = &(c[len]);
|
|
|
|
|
|
|
|
if (ty->buf)
|
|
|
|
{
|
|
|
|
bytes = (ty->buflen + len + 1) * sizeof(int);
|
|
|
|
b = realloc(ty->buf, bytes);
|
|
|
|
if (!b)
|
|
|
|
{
|
2012-06-19 12:40:40 -07:00
|
|
|
ERR("memerr");
|
2012-06-12 03:10:01 -07:00
|
|
|
}
|
2012-06-19 12:40:40 -07:00
|
|
|
INF("realloc add %i + %i", (int)(ty->buflen * sizeof(int)), (int)(len * sizeof(int)));
|
2012-06-30 17:24:30 -07:00
|
|
|
bytes = len * sizeof(Eina_Unicode);
|
2012-06-25 18:38:13 -07:00
|
|
|
memcpy(&(b[ty->buflen]), codepoints, bytes);
|
2012-06-12 03:10:01 -07:00
|
|
|
ty->buf = b;
|
|
|
|
ty->buflen += len;
|
|
|
|
ty->buf[ty->buflen] = 0;
|
|
|
|
c = ty->buf;
|
|
|
|
ce = c + ty->buflen;
|
|
|
|
while (c < ce)
|
|
|
|
{
|
2012-07-13 01:46:33 -07:00
|
|
|
n = _termpty_handle_seq(ty, c, ce);
|
2012-06-12 03:10:01 -07:00
|
|
|
if (n == 0)
|
|
|
|
{
|
2012-06-30 17:24:30 -07:00
|
|
|
Eina_Unicode *tmp = ty->buf;
|
2012-06-12 03:10:01 -07:00
|
|
|
ty->buf = NULL;
|
|
|
|
ty->buflen = 0;
|
2012-06-30 17:24:30 -07:00
|
|
|
bytes = ((char *)ce - (char *)c) + sizeof(Eina_Unicode);
|
|
|
|
INF("malloc til %i", (int)(bytes - sizeof(Eina_Unicode)));
|
2012-06-12 03:10:01 -07:00
|
|
|
ty->buf = malloc(bytes);
|
|
|
|
if (!ty->buf)
|
|
|
|
{
|
2012-06-19 12:40:40 -07:00
|
|
|
ERR("memerr");
|
2012-06-12 03:10:01 -07:00
|
|
|
}
|
|
|
|
bytes = (char *)ce - (char *)c;
|
|
|
|
memcpy(ty->buf, c, bytes);
|
2012-06-30 17:24:30 -07:00
|
|
|
ty->buflen = bytes / sizeof(Eina_Unicode);
|
2012-06-12 03:10:01 -07:00
|
|
|
ty->buf[ty->buflen] = 0;
|
|
|
|
free(tmp);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
c += n;
|
|
|
|
}
|
|
|
|
if (c == ce)
|
|
|
|
{
|
|
|
|
if (ty->buf)
|
|
|
|
{
|
|
|
|
free(ty->buf);
|
|
|
|
ty->buf = NULL;
|
|
|
|
}
|
|
|
|
ty->buflen = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while (c < ce)
|
|
|
|
{
|
2012-07-13 01:46:33 -07:00
|
|
|
n = _termpty_handle_seq(ty, c, ce);
|
2012-06-12 03:10:01 -07:00
|
|
|
if (n == 0)
|
|
|
|
{
|
2012-06-30 17:24:30 -07:00
|
|
|
bytes = ((char *)ce - (char *)c) + sizeof(Eina_Unicode);
|
2012-06-12 03:10:01 -07:00
|
|
|
ty->buf = malloc(bytes);
|
2012-06-30 17:24:30 -07:00
|
|
|
INF("malloc %i", (int)(bytes - sizeof(Eina_Unicode)));
|
2012-06-12 03:10:01 -07:00
|
|
|
if (!ty->buf)
|
|
|
|
{
|
2012-06-19 12:40:40 -07:00
|
|
|
ERR("memerr");
|
2012-06-12 03:10:01 -07:00
|
|
|
}
|
|
|
|
bytes = (char *)ce - (char *)c;
|
|
|
|
memcpy(ty->buf, c, bytes);
|
2012-06-30 17:24:30 -07:00
|
|
|
ty->buflen = bytes / sizeof(Eina_Unicode);
|
2012-06-12 03:10:01 -07:00
|
|
|
ty->buf[ty->buflen] = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
c += n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_pty_size(Termpty *ty)
|
|
|
|
{
|
|
|
|
struct winsize sz;
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
sz.ws_col = ty->w;
|
|
|
|
sz.ws_row = ty->h;
|
|
|
|
sz.ws_xpixel = 0;
|
|
|
|
sz.ws_ypixel = 0;
|
2012-06-19 12:40:40 -07:00
|
|
|
if (ioctl(ty->fd, TIOCSWINSZ, &sz) < 0)
|
|
|
|
ERR("Size set ioctl failed: %s", strerror(errno));
|
2012-06-12 03:10:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
2012-06-17 10:04:17 -07:00
|
|
|
_cb_exe_exit(void *data, int type __UNUSED__, void *event)
|
2012-06-12 03:10:01 -07:00
|
|
|
{
|
|
|
|
Ecore_Exe_Event_Del *ev = event;
|
|
|
|
Termpty *ty = data;
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
if (ev->pid != ty->pid) return ECORE_CALLBACK_PASS_ON;
|
2012-06-20 07:12:26 -07:00
|
|
|
ty->exit_code = ev->exit_code;
|
2012-08-05 02:38:58 -07:00
|
|
|
|
2012-08-05 18:13:20 -07:00
|
|
|
ty->pid = -1;
|
|
|
|
|
2012-08-05 02:38:58 -07:00
|
|
|
if (ty->hand_exe_exit) ecore_event_handler_del(ty->hand_exe_exit);
|
|
|
|
ty->hand_exe_exit = NULL;
|
|
|
|
if (ty->hand_fd) ecore_main_fd_handler_del(ty->hand_fd);
|
|
|
|
ty->hand_fd = NULL;
|
|
|
|
if (ty->fd >= 0) close(ty->fd);
|
|
|
|
ty->fd = -1;
|
|
|
|
if (ty->slavefd >= 0) close(ty->slavefd);
|
|
|
|
ty->slavefd = -1;
|
|
|
|
|
2012-12-27 03:20:32 -08:00
|
|
|
if (ty->cb.exited.func) ty->cb.exited.func(ty->cb.exited.data);
|
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
return ECORE_CALLBACK_PASS_ON;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
2012-06-17 10:04:17 -07:00
|
|
|
_cb_fd_read(void *data, Ecore_Fd_Handler *fd_handler __UNUSED__)
|
2012-06-12 03:10:01 -07:00
|
|
|
{
|
|
|
|
Termpty *ty = data;
|
|
|
|
char buf[4097];
|
2012-06-30 17:24:30 -07:00
|
|
|
Eina_Unicode codepoint[4097];
|
2012-06-12 03:10:01 -07:00
|
|
|
int len, i, j, reads;
|
|
|
|
|
2012-06-22 23:43:02 -07:00
|
|
|
// read up to 64 * 4096 bytes
|
2012-06-12 03:10:01 -07:00
|
|
|
for (reads = 0; reads < 64; reads++)
|
|
|
|
{
|
|
|
|
len = read(ty->fd, buf, sizeof(buf) - 1);
|
|
|
|
if (len <= 0) break;
|
2012-06-22 23:43:02 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
printf(" I: ");
|
|
|
|
int jj;
|
|
|
|
for (jj = 0; jj < len && jj < 100; jj++)
|
|
|
|
{
|
|
|
|
if ((buf[jj] < ' ') || (buf[jj] >= 0x7f))
|
2012-09-28 04:10:58 -07:00
|
|
|
printf("\033[33m%02x\033[0m", (unsigned char)buf[jj]);
|
2012-06-22 23:43:02 -07:00
|
|
|
else
|
|
|
|
printf("%c", buf[jj]);
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
*/
|
2012-06-12 03:10:01 -07:00
|
|
|
buf[len] = 0;
|
2012-06-25 18:38:13 -07:00
|
|
|
// convert UTF8 to codepoint integers
|
2012-06-12 03:10:01 -07:00
|
|
|
j = 0;
|
|
|
|
for (i = 0; i < len;)
|
|
|
|
{
|
|
|
|
int g = 0;
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
if (buf[i])
|
|
|
|
{
|
2013-01-21 18:00:55 -08:00
|
|
|
g = eina_unicode_utf8_next_get(buf, &i);
|
2013-01-17 04:15:02 -08:00
|
|
|
/* i = evas_string_char_next_get(buf, i, &g); */
|
2012-06-12 03:10:01 -07:00
|
|
|
if (i < 0) break;
|
2012-06-19 12:40:40 -07:00
|
|
|
// DBG("(%i) %02x '%c'", j, g, g);
|
2012-06-12 03:10:01 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g = 0;
|
|
|
|
i++;
|
|
|
|
}
|
2012-06-25 18:38:13 -07:00
|
|
|
codepoint[j] = g;
|
2012-06-12 03:10:01 -07:00
|
|
|
j++;
|
|
|
|
}
|
2012-06-25 18:38:13 -07:00
|
|
|
codepoint[j] = 0;
|
2012-06-19 12:40:40 -07:00
|
|
|
// DBG("---------------- handle buf %i", j);
|
2012-06-25 18:38:13 -07:00
|
|
|
_handle_buf(ty, codepoint, j);
|
2012-06-12 03:10:01 -07:00
|
|
|
}
|
|
|
|
if (ty->cb.change.func) ty->cb.change.func(ty->cb.change.data);
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_limit_coord(Termpty *ty, Termstate *state)
|
|
|
|
{
|
|
|
|
state->wrapnext = 0;
|
|
|
|
if (state->cx >= ty->w) state->cx = ty->w - 1;
|
|
|
|
if (state->cy >= ty->h) state->cy = ty->h - 1;
|
|
|
|
if (state->had_cr_x >= ty->w) state->had_cr_x = ty->w - 1;
|
|
|
|
if (state->had_cr_y >= ty->h) state->had_cr_y = ty->h - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
Termpty *
|
2012-09-27 02:33:33 -07:00
|
|
|
termpty_new(const char *cmd, Eina_Bool login_shell, const char *cd, int w, int h, int backscroll)
|
2012-06-12 03:10:01 -07:00
|
|
|
{
|
|
|
|
Termpty *ty;
|
|
|
|
const char *pty;
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
ty = calloc(1, sizeof(Termpty));
|
|
|
|
if (!ty) return NULL;
|
|
|
|
ty->w = w;
|
|
|
|
ty->h = h;
|
|
|
|
ty->backmax = backscroll;
|
|
|
|
|
2012-07-13 01:46:33 -07:00
|
|
|
_termpty_reset_state(ty);
|
2012-06-12 03:10:01 -07:00
|
|
|
ty->save = ty->state;
|
|
|
|
ty->swap = ty->state;
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
ty->screen = calloc(1, sizeof(Termcell) * ty->w * ty->h);
|
|
|
|
if (!ty->screen) goto err;
|
|
|
|
ty->screen2 = calloc(1, sizeof(Termcell) * ty->w * ty->h);
|
|
|
|
if (!ty->screen2) goto err;
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2013-01-21 06:02:32 -08:00
|
|
|
ty->circular_offset = 0;
|
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
ty->fd = posix_openpt(O_RDWR | O_NOCTTY);
|
|
|
|
if (ty->fd < 0) goto err;
|
|
|
|
if (grantpt(ty->fd) != 0) goto err;
|
|
|
|
if (unlockpt(ty->fd) != 0) goto err;
|
|
|
|
pty = ptsname(ty->fd);
|
|
|
|
ty->slavefd = open(pty, O_RDWR | O_NOCTTY);
|
|
|
|
if (ty->slavefd < 0) goto err;
|
|
|
|
fcntl(ty->fd, F_SETFL, O_NDELAY);
|
|
|
|
|
|
|
|
ty->hand_exe_exit = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
|
|
|
|
_cb_exe_exit, ty);
|
|
|
|
ty->pid = fork();
|
|
|
|
if (!ty->pid)
|
|
|
|
{
|
2012-06-17 12:13:03 -07:00
|
|
|
const char *shell = NULL;
|
|
|
|
const char *args[4] = {NULL, NULL, NULL, NULL};
|
|
|
|
Eina_Bool needs_shell;
|
2012-06-12 03:10:01 -07:00
|
|
|
int i;
|
|
|
|
|
2012-08-05 02:38:58 -07:00
|
|
|
if (cd)
|
|
|
|
{
|
|
|
|
if (chdir(cd) != 0)
|
|
|
|
{
|
|
|
|
perror("chdir");
|
|
|
|
ERR("Cannot change to directory '%s'", cd);
|
|
|
|
exit(127);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-17 12:13:03 -07:00
|
|
|
needs_shell = ((!cmd) ||
|
|
|
|
(strpbrk(cmd, " |&;<>()$`\\\"'*?#") != NULL));
|
|
|
|
DBG("cmd='%s' needs_shell=%u", cmd ? cmd : "", needs_shell);
|
|
|
|
|
|
|
|
if (needs_shell)
|
|
|
|
{
|
|
|
|
shell = getenv("SHELL");
|
|
|
|
if (!shell)
|
|
|
|
{
|
|
|
|
uid_t uid = getuid();
|
|
|
|
struct passwd *pw = getpwuid(uid);
|
|
|
|
if (pw) shell = pw->pw_shell;
|
|
|
|
}
|
|
|
|
if (!shell)
|
|
|
|
{
|
|
|
|
WRN("Could not find shell, fallback to /bin/sh");
|
|
|
|
shell = "/bin/sh";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!needs_shell)
|
|
|
|
args[0] = cmd;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
args[0] = shell;
|
|
|
|
if (cmd)
|
|
|
|
{
|
|
|
|
args[1] = "-c";
|
|
|
|
args[2] = cmd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define NC(x) (args[x] != NULL ? args[x] : "")
|
|
|
|
DBG("exec %s %s %s %s", NC(0), NC(1), NC(2), NC(3));
|
|
|
|
#undef NC
|
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
for (i = 0; i < 100; i++)
|
|
|
|
{
|
|
|
|
if (i != ty->slavefd) close(i);
|
|
|
|
}
|
|
|
|
setsid();
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2012-12-27 03:20:32 -08:00
|
|
|
dup2(ty->slavefd, 0);
|
|
|
|
dup2(ty->slavefd, 1);
|
|
|
|
dup2(ty->slavefd, 2);
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2012-12-27 03:20:32 -08:00
|
|
|
if (ioctl(ty->slavefd, TIOCSCTTY, NULL) < 0) exit(1);
|
|
|
|
|
|
|
|
close(ty->fd);
|
|
|
|
close(ty->slavefd);
|
|
|
|
|
2012-06-17 12:13:03 -07:00
|
|
|
/* TODO: should we reset signals here? */
|
2012-06-17 11:28:19 -07:00
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
// pretend to be xterm
|
2012-07-27 02:41:58 -07:00
|
|
|
putenv("TERM=xterm");
|
|
|
|
// putenv("TERM=xterm-256color");
|
2012-07-23 19:16:21 -07:00
|
|
|
putenv("XTERM_256_COLORS=1");
|
2012-09-27 02:33:33 -07:00
|
|
|
if (!login_shell)
|
|
|
|
execvp(args[0], (char *const *)args);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char *cmdfile, *cmd0;
|
|
|
|
|
|
|
|
cmdfile = (char *)args[0];
|
|
|
|
cmd0 = alloca(strlen(cmdfile) + 2);
|
|
|
|
cmd0[0] = '-';
|
|
|
|
strcpy(cmd0 + 1, cmdfile);
|
|
|
|
args[0] = cmd0;
|
|
|
|
execvp(cmdfile, (char *const *)args);
|
|
|
|
}
|
2012-06-17 12:13:03 -07:00
|
|
|
exit(127); /* same as system() for failed commands */
|
2012-06-12 03:10:01 -07:00
|
|
|
}
|
|
|
|
ty->hand_fd = ecore_main_fd_handler_add(ty->fd, ECORE_FD_READ,
|
|
|
|
_cb_fd_read, ty,
|
|
|
|
NULL, NULL);
|
|
|
|
close(ty->slavefd);
|
2012-12-27 03:20:32 -08:00
|
|
|
ty->slavefd = -1;
|
2012-06-12 03:10:01 -07:00
|
|
|
_pty_size(ty);
|
|
|
|
return ty;
|
|
|
|
err:
|
|
|
|
if (ty->screen) free(ty->screen);
|
|
|
|
if (ty->screen2) free(ty->screen2);
|
|
|
|
if (ty->fd >= 0) close(ty->fd);
|
|
|
|
if (ty->slavefd >= 0) close(ty->slavefd);
|
|
|
|
free(ty);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
termpty_free(Termpty *ty)
|
|
|
|
{
|
2013-01-28 16:43:13 -08:00
|
|
|
Termexp *ex;
|
|
|
|
|
|
|
|
EINA_LIST_FREE(ty->block.expecting, ex) free(ex);
|
2013-01-28 08:06:26 -08:00
|
|
|
if (ty->block.blocks) eina_hash_free(ty->block.blocks);
|
|
|
|
if (ty->block.active) eina_list_free(ty->block.active);
|
2012-08-05 21:11:14 -07:00
|
|
|
if (ty->fd >= 0) close(ty->fd);
|
|
|
|
if (ty->slavefd >= 0) close(ty->slavefd);
|
2012-08-05 18:13:20 -07:00
|
|
|
if (ty->pid >= 0)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// in case someone stopped the child - cont it
|
|
|
|
kill(ty->pid, SIGCONT);
|
|
|
|
// signpipe for shells
|
|
|
|
kill(ty->pid, SIGPIPE);
|
|
|
|
// try 400 time (sleeping for 1ms) to check for death of child
|
|
|
|
for (i = 0; i < 400; i++)
|
|
|
|
{
|
|
|
|
int status = 0;
|
|
|
|
|
|
|
|
// poll exit of child pid
|
|
|
|
if (waitpid(ty->pid, &status, WNOHANG) == ty->pid)
|
|
|
|
{
|
|
|
|
// if child exited - break loop and mark pid as done
|
|
|
|
ty->pid = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// after 100ms set sigint
|
|
|
|
if (i == 100) kill(ty->pid, SIGINT);
|
|
|
|
// after 200ms send term signal
|
|
|
|
else if (i == 200) kill(ty->pid, SIGTERM);
|
|
|
|
// after 300ms send quit signal
|
|
|
|
else if (i == 300) kill(ty->pid, SIGQUIT);
|
|
|
|
usleep(1000); // sleep 1ms
|
|
|
|
}
|
|
|
|
// so 400ms and child not gone - KILL!
|
|
|
|
if (ty->pid >= 0)
|
|
|
|
{
|
|
|
|
kill(ty->pid, SIGKILL);
|
|
|
|
ty->pid = -1;
|
|
|
|
}
|
|
|
|
}
|
2012-06-12 03:10:01 -07:00
|
|
|
if (ty->hand_exe_exit) ecore_event_handler_del(ty->hand_exe_exit);
|
|
|
|
if (ty->hand_fd) ecore_main_fd_handler_del(ty->hand_fd);
|
|
|
|
if (ty->prop.title) eina_stringshare_del(ty->prop.title);
|
|
|
|
if (ty->prop.icon) eina_stringshare_del(ty->prop.icon);
|
|
|
|
if (ty->back)
|
|
|
|
{
|
|
|
|
int i;
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
for (i = 0; i < ty->backmax; i++)
|
|
|
|
{
|
|
|
|
if (ty->back[i]) free(ty->back[i]);
|
|
|
|
}
|
|
|
|
free(ty->back);
|
|
|
|
}
|
|
|
|
if (ty->screen) free(ty->screen);
|
|
|
|
if (ty->screen2) free(ty->screen2);
|
|
|
|
if (ty->buf) free(ty->buf);
|
|
|
|
memset(ty, 0, sizeof(Termpty));
|
|
|
|
free(ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
Termcell *
|
|
|
|
termpty_cellrow_get(Termpty *ty, int y, int *wret)
|
|
|
|
{
|
|
|
|
Termsave *ts;
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
if (y >= 0)
|
|
|
|
{
|
|
|
|
if (y >= ty->h) return NULL;
|
|
|
|
*wret = ty->w;
|
2013-01-21 06:02:32 -08:00
|
|
|
/* fprintf(stderr, "getting: %i (%i, %i)\n", y, ty->circular_offset, ty->h); */
|
|
|
|
return &(TERMPTY_SCREEN(ty, 0, y));
|
2012-06-12 03:10:01 -07:00
|
|
|
}
|
|
|
|
if (y < -ty->backmax) return NULL;
|
|
|
|
ts = ty->back[(ty->backmax + ty->backpos + y) % ty->backmax];
|
|
|
|
if (!ts) return NULL;
|
|
|
|
*wret = ts->w;
|
|
|
|
return ts->cell;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
termpty_write(Termpty *ty, const char *input, int len)
|
|
|
|
{
|
2012-08-05 02:38:58 -07:00
|
|
|
if (ty->fd < 0) return;
|
2012-06-19 12:40:40 -07:00
|
|
|
if (write(ty->fd, input, len) < 0) ERR("write %s", strerror(errno));
|
2012-06-12 03:10:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
termpty_resize(Termpty *ty, int w, int h)
|
|
|
|
{
|
|
|
|
Termcell *olds, *olds2;
|
|
|
|
int y, ww, hh, oldw, oldh;
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
if ((ty->w == w) && (ty->h == h)) return;
|
|
|
|
|
|
|
|
olds = ty->screen;
|
|
|
|
olds2 = ty->screen2;
|
|
|
|
oldw = ty->w;
|
|
|
|
oldh = ty->h;
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
ty->w = w;
|
|
|
|
ty->h = h;
|
|
|
|
ty->state.had_cr = 0;
|
|
|
|
_limit_coord(ty, &(ty->state));
|
|
|
|
_limit_coord(ty, &(ty->swap));
|
|
|
|
_limit_coord(ty, &(ty->save));
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
ty->screen = calloc(1, sizeof(Termcell) * ty->w * ty->h);
|
|
|
|
if (!ty->screen)
|
|
|
|
{
|
|
|
|
ty->screen2 = NULL;
|
|
|
|
ERR("memerr");
|
|
|
|
}
|
|
|
|
ty->screen2 = calloc(1, sizeof(Termcell) * ty->w * ty->h);
|
|
|
|
if (!ty->screen2)
|
|
|
|
{
|
|
|
|
ERR("memerr");
|
|
|
|
}
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
ww = ty->w;
|
|
|
|
hh = ty->h;
|
|
|
|
if (ww > oldw) ww = oldw;
|
|
|
|
if (hh > oldh) hh = oldh;
|
|
|
|
|
2013-01-21 06:02:32 -08:00
|
|
|
// FIXME: handle pointer copy here
|
2012-06-12 03:10:01 -07:00
|
|
|
for (y = 0; y < hh; y++)
|
|
|
|
{
|
|
|
|
Termcell *c1, *c2;
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
c1 = &(olds[y * oldw]);
|
2013-01-21 06:02:32 -08:00
|
|
|
c2 = &(TERMPTY_SCREEN(ty, 0, y));
|
2012-07-13 01:46:33 -07:00
|
|
|
_termpty_text_copy(ty, c1, c2, ww);
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
c1 = &(olds2[y * oldw]);
|
|
|
|
c2 = &(ty->screen2[y * ty->w]);
|
2012-07-13 01:46:33 -07:00
|
|
|
_termpty_text_copy(ty, c1, c2, ww);
|
2012-06-12 03:10:01 -07:00
|
|
|
}
|
|
|
|
|
2013-01-21 06:02:32 -08:00
|
|
|
ty->circular_offset = 0;
|
2012-06-12 03:10:01 -07:00
|
|
|
free(olds);
|
|
|
|
free(olds2);
|
|
|
|
|
|
|
|
_pty_size(ty);
|
|
|
|
}
|
2012-06-16 10:31:54 -07:00
|
|
|
|
|
|
|
void
|
|
|
|
termpty_backscroll_set(Termpty *ty, int size)
|
|
|
|
{
|
|
|
|
int i;
|
2012-06-17 10:04:17 -07:00
|
|
|
|
2012-06-16 10:31:54 -07:00
|
|
|
if (ty->backmax == size) return;
|
|
|
|
|
|
|
|
if (ty->back)
|
|
|
|
{
|
|
|
|
for (i = 0; i < ty->backmax; i++)
|
|
|
|
{
|
|
|
|
if (ty->back[i]) free(ty->back[i]);
|
|
|
|
}
|
|
|
|
free(ty->back);
|
|
|
|
}
|
2012-06-18 04:18:46 -07:00
|
|
|
if (size > 0)
|
|
|
|
ty->back = calloc(1, sizeof(Termsave *) * size);
|
|
|
|
else
|
|
|
|
ty->back = NULL;
|
2012-06-16 10:31:54 -07:00
|
|
|
ty->backscroll_num = 0;
|
|
|
|
ty->backpos = 0;
|
|
|
|
ty->backmax = size;
|
|
|
|
}
|
2012-10-09 10:09:26 -07:00
|
|
|
|
|
|
|
pid_t
|
|
|
|
termpty_pid_get(const Termpty *ty)
|
|
|
|
{
|
|
|
|
return ty->pid;
|
|
|
|
}
|
2013-01-28 08:06:26 -08:00
|
|
|
|
|
|
|
void
|
|
|
|
termpty_block_free(Termblock *tb)
|
|
|
|
{
|
|
|
|
if (tb->path) eina_stringshare_del(tb->path);
|
|
|
|
if (tb->obj) evas_object_del(tb->obj);
|
|
|
|
free(tb);
|
|
|
|
}
|
|
|
|
|
|
|
|
Termblock *
|
|
|
|
termpty_block_new(Termpty *ty, int w, int h, const char *path)
|
|
|
|
{
|
|
|
|
Termblock *tb;
|
|
|
|
int id;
|
|
|
|
|
|
|
|
id = ty->block.curid;
|
|
|
|
if (!ty->block.blocks)
|
|
|
|
ty->block.blocks = eina_hash_int32_new((Eina_Free_Cb)termpty_block_free);
|
|
|
|
if (!ty->block.blocks) return NULL;
|
|
|
|
tb = eina_hash_find(ty->block.blocks, &id);
|
|
|
|
if (tb)
|
|
|
|
{
|
|
|
|
if (tb->active)
|
|
|
|
ty->block.active = eina_list_remove(ty->block.active, tb);
|
|
|
|
eina_hash_del(ty->block.blocks, &id, tb);
|
|
|
|
}
|
|
|
|
tb = calloc(1, sizeof(Termblock));
|
|
|
|
if (!tb) return NULL;
|
|
|
|
tb->id = id;
|
|
|
|
tb->w = w;
|
|
|
|
tb->h = h;
|
|
|
|
tb->path = eina_stringshare_add(path);
|
|
|
|
eina_hash_add(ty->block.blocks, &id, tb);
|
|
|
|
ty->block.curid++;
|
|
|
|
if (ty->block.curid >= 8192) ty->block.curid = 0;
|
|
|
|
return tb;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-01-28 16:43:13 -08:00
|
|
|
termpty_block_insert(Termpty *ty, int ch, Termblock *blk)
|
2013-01-28 08:06:26 -08:00
|
|
|
{
|
|
|
|
// bit 0-8 = y (9b 0->511)
|
|
|
|
// bit 9-17 = x (9b 0->511)
|
|
|
|
// bit 18-30 = id (13b 0->8191)
|
|
|
|
// bit 31 = 1
|
|
|
|
//
|
|
|
|
// fg/bg = 8+8bit unused. (use for extra id bits? so 16 + 13 == 29bit?)
|
|
|
|
//
|
|
|
|
// cp = (1 << 31) | ((id 0x1fff) << 18) | ((x & 0x1ff) << 9) | (y & 0x1ff);
|
2013-01-28 16:43:13 -08:00
|
|
|
Termexp *ex;
|
|
|
|
|
|
|
|
ex = calloc(1, sizeof(Termexp));
|
|
|
|
if (!ex) return;
|
|
|
|
ex->ch = ch;
|
|
|
|
ex->left = blk->w * blk->h;
|
|
|
|
ex->x = 0;
|
|
|
|
ex->y = 0;
|
|
|
|
ex->id = blk->id;
|
|
|
|
ex->w = blk->w;
|
|
|
|
ex->h = blk->h;
|
|
|
|
ty->block.expecting = eina_list_append(ty->block.expecting, ex);
|
2013-01-28 08:06:26 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
termpty_block_id_get(Termcell *cell, int *x, int *y)
|
|
|
|
{
|
|
|
|
int id;
|
|
|
|
|
|
|
|
if (!(cell->codepoint & 0x80000000)) return -1;
|
|
|
|
id = (cell->codepoint >> 18) & 0x1fff;
|
|
|
|
*x = (cell->codepoint >> 9) & 0x1ff;
|
|
|
|
*y = cell->codepoint & 0x1ff;
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
Termblock *
|
|
|
|
termpty_block_get(Termpty *ty, int id)
|
|
|
|
{
|
|
|
|
return eina_hash_find(ty->block.blocks, &id);
|
|
|
|
}
|