2012-06-17 09:28:02 -07:00
|
|
|
#include "private.h"
|
2012-06-12 03:10:01 -07:00
|
|
|
#include <Elementary.h>
|
2018-02-04 15:07:47 -08:00
|
|
|
#include <Ecore_Input.h>
|
|
|
|
#include <Ecore_IMF.h>
|
|
|
|
#include <Ecore_IMF_Evas.h>
|
2012-06-12 03:10:01 -07:00
|
|
|
#include "termpty.h"
|
2012-07-13 01:46:33 -07:00
|
|
|
#include "termptyesc.h"
|
|
|
|
#include "termptyops.h"
|
2013-05-03 19:44:20 -07:00
|
|
|
#include "termptysave.h"
|
2013-09-22 08:10:39 -07:00
|
|
|
#include "termio.h"
|
2018-02-04 15:07:47 -08:00
|
|
|
#include "keyin.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>
|
2013-09-22 08:10:39 -07:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <termios.h>
|
2015-02-23 14:32:12 -08:00
|
|
|
#if defined (__sun) || defined (__sun__)
|
|
|
|
# include <stropts.h>
|
|
|
|
#endif
|
2015-04-06 09:08:23 -07:00
|
|
|
#include <assert.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)
|
2014-07-21 14:51:26 -07:00
|
|
|
EINA_LOG_CRIT("Could not create logging domain '%s'.", "termpty");
|
2012-06-19 12:53:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
termpty_shutdown(void)
|
|
|
|
{
|
|
|
|
if (_termpty_log_dom < 0) return;
|
|
|
|
eina_log_domain_unregister(_termpty_log_dom);
|
|
|
|
_termpty_log_dom = -1;
|
|
|
|
}
|
|
|
|
|
2018-02-04 15:07:47 -08:00
|
|
|
|
|
|
|
Eina_Bool
|
|
|
|
termpty_can_handle_key(const Termpty *ty,
|
|
|
|
const Keys_Handler *khdl,
|
|
|
|
const Evas_Event_Key_Down *ev)
|
|
|
|
{
|
|
|
|
// if term app asked for kbd lock - dont handle here
|
|
|
|
if (ty->termstate.kbd_lock)
|
|
|
|
return EINA_FALSE;
|
|
|
|
// if app asked us to not do autorepeat - ignore press if is it is the same
|
|
|
|
// timestamp as last one
|
|
|
|
if ((ty->termstate.no_autorepeat) &&
|
|
|
|
(ev->timestamp == khdl->last_keyup))
|
|
|
|
return EINA_FALSE;
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-11-02 15:07:22 -08:00
|
|
|
void
|
|
|
|
termpty_handle_buf(Termpty *ty, const Eina_Unicode *codepoints, int len)
|
2012-06-12 03:10:01 -07:00
|
|
|
{
|
2017-12-17 22:16:54 -08:00
|
|
|
Eina_Unicode *c, *ce, *c2, *b, *d;
|
2012-06-30 17:24:30 -07:00
|
|
|
int n, bytes;
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2014-01-22 14:22:42 -08:00
|
|
|
c = (Eina_Unicode *)codepoints;
|
2012-06-12 03:10:01 -07:00
|
|
|
ce = &(c[len]);
|
|
|
|
|
|
|
|
if (ty->buf)
|
|
|
|
{
|
2017-12-17 22:16:54 -08:00
|
|
|
if (!ty->buf) ty->buf_have_zero = EINA_FALSE;
|
2012-06-12 03:10:01 -07:00
|
|
|
bytes = (ty->buflen + len + 1) * sizeof(int);
|
|
|
|
b = realloc(ty->buf, bytes);
|
|
|
|
if (!b)
|
|
|
|
{
|
2014-07-21 14:51:26 -07:00
|
|
|
ERR(_("memerr: %s"), strerror(errno));
|
2014-03-24 05:38:42 -07:00
|
|
|
return;
|
2012-06-12 03:10:01 -07:00
|
|
|
}
|
2014-07-21 14:51:26 -07:00
|
|
|
DBG("realloc add %i + %i", (int)(ty->buflen * sizeof(int)), (int)(len * sizeof(int)));
|
2017-12-17 22:16:54 -08:00
|
|
|
if (!ty->buf_have_zero)
|
|
|
|
{
|
|
|
|
d = &(b[ty->buflen]);
|
|
|
|
ce = (Eina_Unicode *)codepoints + len;
|
|
|
|
for (c = (Eina_Unicode *)codepoints; c < ce; c++, d++)
|
|
|
|
{
|
|
|
|
*d = *c;
|
|
|
|
if (*c == 0x0)
|
|
|
|
{
|
|
|
|
ty->buf_have_zero = EINA_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (; c < ce; c++, d++) *d = *c;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bytes = len * sizeof(Eina_Unicode);
|
|
|
|
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)
|
|
|
|
{
|
2014-09-15 14:30:48 -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);
|
2014-07-21 14:51:26 -07:00
|
|
|
DBG("malloc till %i", (int)(bytes - sizeof(Eina_Unicode)));
|
2012-06-12 03:10:01 -07:00
|
|
|
ty->buf = malloc(bytes);
|
|
|
|
if (!ty->buf)
|
|
|
|
{
|
2014-07-21 14:51:26 -07:00
|
|
|
ERR(_("memerr: %s"), strerror(errno));
|
2014-03-25 13:43:49 -07:00
|
|
|
return;
|
2012-06-12 03:10:01 -07:00
|
|
|
}
|
2017-12-17 22:16:54 -08:00
|
|
|
ty->buf_have_zero = EINA_FALSE;
|
|
|
|
for (d = ty->buf, c2 = c; c2 < ce; c2++, d++)
|
|
|
|
{
|
|
|
|
*d = *c2;
|
|
|
|
if (*c2 == 0x0)
|
|
|
|
{
|
|
|
|
ty->buf_have_zero = EINA_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (; c2 < ce; c2++, d++) *d = *c2;
|
2012-06-12 03:10:01 -07:00
|
|
|
bytes = (char *)ce - (char *)c;
|
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)
|
|
|
|
{
|
2017-12-17 22:16:54 -08:00
|
|
|
ty->buf_have_zero = EINA_FALSE;
|
2012-06-12 03:10:01 -07:00
|
|
|
free(ty->buf);
|
|
|
|
ty->buf = NULL;
|
|
|
|
}
|
|
|
|
ty->buflen = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-12-17 22:16:54 -08:00
|
|
|
ty->buf_have_zero = EINA_TRUE;
|
2012-06-12 03:10:01 -07:00
|
|
|
while (c < ce)
|
|
|
|
{
|
2014-09-15 14:30:48 -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);
|
2017-12-17 22:16:54 -08:00
|
|
|
ty->buf_have_zero = EINA_FALSE;
|
2012-06-12 03:10:01 -07:00
|
|
|
ty->buf = malloc(bytes);
|
2014-07-21 14:51:26 -07:00
|
|
|
DBG("malloc %i", (int)(bytes - sizeof(Eina_Unicode)));
|
2012-06-12 03:10:01 -07:00
|
|
|
if (!ty->buf)
|
|
|
|
{
|
2014-07-21 14:51:26 -07:00
|
|
|
ERR(_("memerr: %s"), strerror(errno));
|
2012-06-12 03:10:01 -07:00
|
|
|
}
|
2014-03-24 05:37:07 -07:00
|
|
|
else
|
|
|
|
{
|
2017-12-17 22:16:54 -08:00
|
|
|
ty->buf_have_zero = EINA_FALSE;
|
|
|
|
for (d = ty->buf, c2 = c; c2 < ce; c2++, d++)
|
|
|
|
{
|
|
|
|
*d = *c2;
|
|
|
|
if (*c2 == 0x0)
|
|
|
|
{
|
|
|
|
ty->buf_have_zero = EINA_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (; c2 < ce; c2++, d++) *d = *c2;
|
2014-03-24 05:37:07 -07:00
|
|
|
bytes = (char *)ce - (char *)c;
|
|
|
|
ty->buflen = bytes / sizeof(Eina_Unicode);
|
|
|
|
ty->buf[ty->buflen] = 0;
|
|
|
|
}
|
2012-06-12 03:10:01 -07:00
|
|
|
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)
|
2014-07-21 14:51:26 -07:00
|
|
|
ERR(_("Size set ioctl failed: %s"), strerror(errno));
|
2012-06-12 03:10:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
2016-12-12 18:53:50 -08:00
|
|
|
_fd_read_do(Termpty *ty, Ecore_Fd_Handler *fd_handler, Eina_Bool false_on_empty)
|
2012-06-12 03:10:01 -07:00
|
|
|
{
|
|
|
|
char buf[4097];
|
2012-06-30 17:24:30 -07:00
|
|
|
Eina_Unicode codepoint[4097];
|
2013-05-03 03:53:41 -07:00
|
|
|
int len, i, j, k, reads;
|
2012-06-12 03:10:01 -07:00
|
|
|
|
2015-09-20 14:26:26 -07:00
|
|
|
if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
|
|
|
|
{
|
|
|
|
ERR("error while reading from tty slave fd");
|
|
|
|
return ECORE_CALLBACK_CANCEL;
|
|
|
|
}
|
2016-12-05 13:45:44 -08:00
|
|
|
if (ty->fd == -1)
|
|
|
|
return ECORE_CALLBACK_CANCEL;
|
2015-09-20 14:26:26 -07:00
|
|
|
|
2016-12-06 12:49:15 -08:00
|
|
|
/* it seems the BSDs can not read from this side of the pair if the other side
|
|
|
|
* is closed */
|
|
|
|
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
|
|
|
if (ty->pid == -1)
|
|
|
|
return ECORE_CALLBACK_CANCEL;
|
|
|
|
#endif
|
|
|
|
|
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++)
|
|
|
|
{
|
2013-04-28 13:47:14 -07:00
|
|
|
char *rbuf = buf;
|
|
|
|
len = sizeof(buf) - 1;
|
|
|
|
|
|
|
|
for (i = 0; i < (int)sizeof(ty->oldbuf) && ty->oldbuf[i] & 0x80; i++)
|
|
|
|
{
|
|
|
|
*rbuf = ty->oldbuf[i];
|
|
|
|
rbuf++;
|
|
|
|
len--;
|
|
|
|
}
|
2016-12-05 14:39:29 -08:00
|
|
|
errno = 0;
|
2013-04-28 13:47:14 -07:00
|
|
|
len = read(ty->fd, rbuf, len);
|
2016-12-05 14:39:29 -08:00
|
|
|
if ((len < 0 && errno != EAGAIN) ||
|
|
|
|
(len == 0 && errno != 0))
|
2015-09-20 14:26:26 -07:00
|
|
|
{
|
2016-12-04 14:24:28 -08:00
|
|
|
/* Do not print error if the child has exited */
|
|
|
|
if (ty->pid != -1)
|
|
|
|
{
|
|
|
|
ERR("error while reading from tty slave fd: %s", strerror(errno));
|
|
|
|
}
|
2016-12-05 13:45:44 -08:00
|
|
|
close(ty->fd);
|
|
|
|
ty->fd = -1;
|
|
|
|
if (ty->hand_fd) ecore_main_fd_handler_del(ty->hand_fd);
|
|
|
|
ty->hand_fd = NULL;
|
2016-12-04 14:24:28 -08:00
|
|
|
return ECORE_CALLBACK_CANCEL;
|
2015-09-20 14:26:26 -07:00
|
|
|
}
|
2012-06-12 03:10:01 -07:00
|
|
|
if (len <= 0) break;
|
2013-04-28 13:47:14 -07:00
|
|
|
|
|
|
|
for (i = 0; i < (int)sizeof(ty->oldbuf); i++)
|
|
|
|
ty->oldbuf[i] = 0;
|
|
|
|
|
|
|
|
len += rbuf - buf;
|
|
|
|
|
|
|
|
/*
|
2012-06-22 23:43:02 -07:00
|
|
|
printf(" I: ");
|
|
|
|
int jj;
|
2013-04-28 13:47:14 -07:00
|
|
|
for (jj = 0; jj < len; jj++)
|
2012-06-22 23:43:02 -07:00
|
|
|
{
|
|
|
|
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");
|
2013-04-28 13:47:14 -07:00
|
|
|
*/
|
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;)
|
|
|
|
{
|
2013-04-28 13:47:14 -07:00
|
|
|
int g = 0, prev_i = i;
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
if (buf[i])
|
|
|
|
{
|
2013-01-28 19:52:57 -08:00
|
|
|
#if (EINA_VERSION_MAJOR > 1) || (EINA_VERSION_MINOR >= 8)
|
2013-01-21 18:00:55 -08:00
|
|
|
g = eina_unicode_utf8_next_get(buf, &i);
|
2013-05-03 03:53:41 -07:00
|
|
|
if ((0xdc80 <= g) && (g <= 0xdcff) &&
|
|
|
|
(len - prev_i) <= (int)sizeof(ty->oldbuf))
|
2013-04-28 13:47:14 -07:00
|
|
|
#else
|
2013-01-28 19:52:57 -08:00
|
|
|
i = evas_string_char_next_get(buf, i, &g);
|
2013-04-28 13:47:14 -07:00
|
|
|
if (i < 0 &&
|
2013-05-03 03:53:41 -07:00
|
|
|
(len - prev_i) <= (int)sizeof(ty->oldbuf))
|
2013-04-28 13:47:14 -07:00
|
|
|
#endif
|
|
|
|
{
|
|
|
|
for (k = 0;
|
2013-05-03 03:53:41 -07:00
|
|
|
(k < (int)sizeof(ty->oldbuf)) &&
|
|
|
|
(k < (len - prev_i));
|
2013-04-28 13:47:14 -07:00
|
|
|
k++)
|
|
|
|
{
|
|
|
|
ty->oldbuf[k] = buf[prev_i+k];
|
|
|
|
}
|
|
|
|
DBG("failure at %d/%d/%d", prev_i, i, len);
|
|
|
|
break;
|
|
|
|
}
|
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);
|
2015-11-02 15:07:22 -08:00
|
|
|
termpty_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);
|
2015-11-11 16:53:32 -08:00
|
|
|
#ifdef ENABLE_FUZZING
|
2015-09-20 14:26:26 -07:00
|
|
|
if (len <= 0)
|
|
|
|
{
|
2015-11-01 09:39:39 -08:00
|
|
|
ty->exit_code = 0;
|
|
|
|
ty->pid = -1;
|
|
|
|
|
|
|
|
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;
|
|
|
|
ty->fd = -1;
|
|
|
|
ty->slavefd = -1;
|
|
|
|
if (ty->cb.exited.func)
|
|
|
|
ty->cb.exited.func(ty->cb.exited.data);
|
2015-09-20 14:26:26 -07:00
|
|
|
return ECORE_CALLBACK_CANCEL;
|
|
|
|
}
|
2015-11-11 16:53:32 -08:00
|
|
|
#endif
|
2016-12-12 18:53:50 -08:00
|
|
|
if ((false_on_empty) && (len <= 0)) return ECORE_CALLBACK_CANCEL;
|
2012-06-12 03:10:01 -07:00
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
2016-12-12 18:53:50 -08:00
|
|
|
static Eina_Bool
|
|
|
|
_cb_fd_read(void *data, Ecore_Fd_Handler *fd_handler)
|
|
|
|
{
|
|
|
|
return _fd_read_do(data, fd_handler, EINA_FALSE);
|
|
|
|
}
|
|
|
|
|
2016-12-04 14:24:28 -08:00
|
|
|
static Eina_Bool
|
|
|
|
_cb_exe_exit(void *data,
|
|
|
|
int _type EINA_UNUSED,
|
|
|
|
void *event)
|
|
|
|
{
|
|
|
|
Ecore_Exe_Event_Del *ev = event;
|
|
|
|
Termpty *ty = data;
|
|
|
|
Eina_Bool res;
|
|
|
|
|
|
|
|
if (ev->pid != ty->pid) return ECORE_CALLBACK_PASS_ON;
|
|
|
|
ty->exit_code = ev->exit_code;
|
|
|
|
|
|
|
|
ty->pid = -1;
|
|
|
|
|
|
|
|
if (ty->hand_exe_exit) ecore_event_handler_del(ty->hand_exe_exit);
|
|
|
|
ty->hand_exe_exit = NULL;
|
|
|
|
|
|
|
|
/* Read everything till the end */
|
2016-12-05 12:53:15 -08:00
|
|
|
res = ECORE_CALLBACK_PASS_ON;
|
|
|
|
while (ty->hand_fd && res != ECORE_CALLBACK_CANCEL)
|
2016-12-04 14:24:28 -08:00
|
|
|
{
|
2016-12-12 18:53:50 -08:00
|
|
|
res = _fd_read_do(ty, ty->hand_fd, EINA_TRUE);
|
2016-12-04 14:24:28 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (ty->cb.exited.func) ty->cb.exited.func(ty->cb.exited.data);
|
|
|
|
|
|
|
|
return ECORE_CALLBACK_PASS_ON;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
static void
|
2015-04-19 10:59:29 -07:00
|
|
|
_limit_coord(Termpty *ty)
|
2012-06-12 03:10:01 -07:00
|
|
|
{
|
2015-06-02 13:48:50 -07:00
|
|
|
TERMPTY_RESTRICT_FIELD(ty->termstate.had_cr_x, 0, ty->w);
|
|
|
|
TERMPTY_RESTRICT_FIELD(ty->termstate.had_cr_y, 0, ty->h);
|
|
|
|
|
|
|
|
TERMPTY_RESTRICT_FIELD(ty->cursor_state.cx, 0, ty->w);
|
|
|
|
TERMPTY_RESTRICT_FIELD(ty->cursor_state.cy, 0, ty->h);
|
|
|
|
|
2016-10-17 15:14:19 -07:00
|
|
|
TERMPTY_RESTRICT_FIELD(ty->cursor_save[0].cx, 0, ty->w);
|
|
|
|
TERMPTY_RESTRICT_FIELD(ty->cursor_save[0].cy, 0, ty->h);
|
|
|
|
TERMPTY_RESTRICT_FIELD(ty->cursor_save[1].cx, 0, ty->w);
|
|
|
|
TERMPTY_RESTRICT_FIELD(ty->cursor_save[1].cy, 0, ty->h);
|
2012-06-12 03:10:01 -07:00
|
|
|
}
|
|
|
|
|
2017-05-16 15:05:15 -07:00
|
|
|
void
|
|
|
|
termpty_resize_tabs(Termpty *ty, int old_w, int new_w)
|
2016-12-18 09:48:03 -08:00
|
|
|
{
|
|
|
|
unsigned int *new_tabs;
|
|
|
|
int i;
|
2017-01-30 20:03:36 -08:00
|
|
|
size_t nb_elems, n;
|
2016-12-18 09:48:03 -08:00
|
|
|
|
2017-01-30 20:03:36 -08:00
|
|
|
if ((new_w == old_w) && ty->tabs) return;
|
2016-12-18 09:48:03 -08:00
|
|
|
|
2017-01-30 20:03:36 -08:00
|
|
|
nb_elems = ROUND_UP(new_w, 8);
|
2016-12-18 09:48:03 -08:00
|
|
|
new_tabs = calloc(nb_elems, sizeof(unsigned int));
|
2017-01-30 20:03:36 -08:00
|
|
|
if (!new_tabs) return;
|
2016-12-18 09:48:03 -08:00
|
|
|
|
|
|
|
if (ty->tabs)
|
|
|
|
{
|
2017-01-30 20:03:36 -08:00
|
|
|
n = old_w;
|
|
|
|
if (nb_elems < n) n = nb_elems;
|
|
|
|
if (n > 0) memcpy(new_tabs, ty->tabs, n * sizeof(unsigned int));
|
2016-12-18 09:48:03 -08:00
|
|
|
free(ty->tabs);
|
|
|
|
}
|
|
|
|
|
|
|
|
ty->tabs = new_tabs;
|
|
|
|
for (i = ROUND_UP(ty->w, TAB_WIDTH); i < new_w; i += TAB_WIDTH)
|
|
|
|
{
|
|
|
|
TAB_SET(ty, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-24 09:39:42 -08:00
|
|
|
static Eina_Bool
|
|
|
|
_is_shell_valid(const char *cmd)
|
|
|
|
{
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
if (!cmd)
|
|
|
|
return EINA_FALSE;
|
|
|
|
if (cmd[0] == '\0')
|
|
|
|
return EINA_FALSE;
|
|
|
|
if (cmd[0] != '/')
|
|
|
|
{
|
|
|
|
ERR("shell command '%s' is not an absolute path", cmd);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
if (stat(cmd, &st) != 0)
|
|
|
|
{
|
|
|
|
ERR("shell command '%s' can not be stat(): %s", cmd, strerror(errno));
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
if ((st.st_mode & S_IFMT) != S_IFREG)
|
|
|
|
{
|
|
|
|
ERR("shell command '%s' is not a regular file", cmd);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
if ((st.st_mode & S_IXOTH) == 0)
|
|
|
|
{
|
|
|
|
ERR("shell command '%s' is not executable", cmd);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
Termpty *
|
2013-06-16 13:32:50 -07:00
|
|
|
termpty_new(const char *cmd, Eina_Bool login_shell, const char *cd,
|
2013-09-22 08:10:39 -07:00
|
|
|
int w, int h, int backscroll, Eina_Bool xterm_256color,
|
2017-08-28 12:36:48 -07:00
|
|
|
Eina_Bool erase_is_del, const char *emotion_mod,
|
|
|
|
const char *title)
|
2012-06-12 03:10:01 -07:00
|
|
|
{
|
|
|
|
Termpty *ty;
|
|
|
|
const char *pty;
|
2013-09-21 15:15:56 -07:00
|
|
|
int mode;
|
2014-01-29 13:57:49 -08:00
|
|
|
struct termios t;
|
2014-12-16 13:09:44 -08:00
|
|
|
Eina_Bool needs_shell;
|
|
|
|
const char *shell = NULL;
|
|
|
|
const char *args[4] = {NULL, NULL, NULL, NULL};
|
|
|
|
const char *arg0;
|
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;
|
2015-04-06 09:08:23 -07:00
|
|
|
ty->backsize = backscroll;
|
2012-06-12 03:10:01 -07:00
|
|
|
|
|
|
|
ty->screen = calloc(1, sizeof(Termcell) * ty->w * ty->h);
|
2013-08-29 20:14:18 -07:00
|
|
|
if (!ty->screen)
|
|
|
|
{
|
2014-07-22 14:38:03 -07:00
|
|
|
ERR("Allocation of term %s %ix%i failed: %s",
|
2014-07-21 14:51:26 -07:00
|
|
|
"screen", ty->w, ty->h, strerror(errno));
|
2013-08-29 20:14:18 -07:00
|
|
|
goto err;
|
|
|
|
}
|
2012-06-12 03:10:01 -07:00
|
|
|
ty->screen2 = calloc(1, sizeof(Termcell) * ty->w * ty->h);
|
2013-08-29 20:14:18 -07:00
|
|
|
if (!ty->screen2)
|
|
|
|
{
|
2014-07-22 14:38:03 -07:00
|
|
|
ERR("Allocation of term %s %ix%i failed: %s",
|
2014-07-21 14:51:26 -07:00
|
|
|
"screen2", ty->w, ty->h, strerror(errno));
|
2013-08-29 20:14:18 -07:00
|
|
|
goto err;
|
|
|
|
}
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2017-05-16 15:05:15 -07:00
|
|
|
termpty_resize_tabs(ty, 0, w);
|
2016-12-18 09:48:03 -08:00
|
|
|
|
|
|
|
termpty_reset_state(ty);
|
|
|
|
|
2013-01-21 06:02:32 -08:00
|
|
|
ty->circular_offset = 0;
|
|
|
|
|
2015-11-01 09:39:39 -08:00
|
|
|
#ifdef ENABLE_FUZZING
|
|
|
|
ty->fd = STDIN_FILENO;
|
|
|
|
ty->hand_fd = ecore_main_fd_handler_add(ty->fd,
|
|
|
|
ECORE_FD_READ | ECORE_FD_ERROR,
|
|
|
|
_cb_fd_read, ty,
|
|
|
|
NULL, NULL);
|
|
|
|
_pty_size(ty);
|
|
|
|
termpty_save_register(ty);
|
|
|
|
return ty;
|
|
|
|
#endif
|
2015-09-20 14:26:26 -07:00
|
|
|
|
2014-12-16 13:09:44 -08:00
|
|
|
needs_shell = ((!cmd) ||
|
|
|
|
(strpbrk(cmd, " |&;<>()$`\\\"'*?#") != NULL));
|
|
|
|
DBG("cmd='%s' needs_shell=%u", cmd ? cmd : "", needs_shell);
|
|
|
|
|
|
|
|
if (needs_shell)
|
|
|
|
{
|
|
|
|
shell = getenv("SHELL");
|
2016-12-24 09:39:42 -08:00
|
|
|
if (!_is_shell_valid(shell))
|
|
|
|
shell = NULL;
|
2014-12-16 13:09:44 -08:00
|
|
|
if (!shell)
|
|
|
|
{
|
|
|
|
uid_t uid = getuid();
|
|
|
|
struct passwd *pw = getpwuid(uid);
|
|
|
|
if (pw) shell = pw->pw_shell;
|
|
|
|
}
|
|
|
|
if (!shell)
|
|
|
|
{
|
|
|
|
WRN(_("Could not find shell, falling back to %s"), "/bin/sh");
|
|
|
|
shell = "/bin/sh";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!needs_shell)
|
|
|
|
args[0] = cmd;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
args[0] = shell;
|
|
|
|
if (cmd)
|
|
|
|
{
|
|
|
|
args[1] = "-c";
|
|
|
|
args[2] = cmd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
arg0 = strrchr(args[0], '/');
|
|
|
|
if (!arg0) arg0 = args[0];
|
|
|
|
else arg0++;
|
2017-08-28 12:40:05 -07:00
|
|
|
ty->prop.title = eina_stringshare_add(title? title : arg0);
|
2014-12-16 13:09:44 -08:00
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
ty->fd = posix_openpt(O_RDWR | O_NOCTTY);
|
2013-08-29 20:14:18 -07:00
|
|
|
if (ty->fd < 0)
|
|
|
|
{
|
2014-07-21 14:51:26 -07:00
|
|
|
ERR(_("Function %s failed: %s"), "posix_openpt()", strerror(errno));
|
2013-08-29 20:14:18 -07:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (grantpt(ty->fd) != 0)
|
|
|
|
{
|
2014-07-21 14:51:26 -07:00
|
|
|
WRN(_("Function %s failed: %s"), "grantpt()", strerror(errno));
|
2013-08-29 20:14:18 -07:00
|
|
|
}
|
|
|
|
if (unlockpt(ty->fd) != 0)
|
|
|
|
{
|
2014-07-21 14:51:26 -07:00
|
|
|
ERR(_("Function %s failed: %s"), "unlockpt()", strerror(errno));
|
2013-08-29 20:14:18 -07:00
|
|
|
goto err;
|
|
|
|
}
|
2012-06-12 03:10:01 -07:00
|
|
|
pty = ptsname(ty->fd);
|
|
|
|
ty->slavefd = open(pty, O_RDWR | O_NOCTTY);
|
2013-08-29 20:14:18 -07:00
|
|
|
if (ty->slavefd < 0)
|
|
|
|
{
|
2014-07-21 14:51:26 -07:00
|
|
|
ERR(_("open() of pty '%s' failed: %s"), pty, strerror(errno));
|
2013-08-29 20:14:18 -07:00
|
|
|
goto err;
|
|
|
|
}
|
2016-12-04 14:24:28 -08:00
|
|
|
|
2013-09-21 15:15:56 -07:00
|
|
|
mode = fcntl(ty->fd, F_GETFL, 0);
|
|
|
|
if (mode < 0)
|
|
|
|
{
|
2014-07-21 14:51:26 -07:00
|
|
|
ERR(_("fcntl() on pty '%s' failed: %s"), pty, strerror(errno));
|
2013-09-21 15:15:56 -07:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (!(mode & O_NDELAY))
|
2015-09-20 14:26:26 -07:00
|
|
|
if (fcntl(ty->fd, F_SETFL, mode | O_NDELAY))
|
|
|
|
{
|
|
|
|
ERR(_("fcntl() on pty '%s' failed: %s"), pty, strerror(errno));
|
|
|
|
goto err;
|
|
|
|
}
|
2012-06-12 03:10:01 -07:00
|
|
|
|
2015-02-23 14:32:12 -08:00
|
|
|
#if defined (__sun) || defined (__sun__)
|
|
|
|
if (ioctl(ty->slavefd, I_PUSH, "ptem") < 0
|
|
|
|
|| ioctl(ty->slavefd, I_PUSH, "ldterm") < 0
|
|
|
|
|| ioctl(ty->slavefd, I_PUSH, "ttcompat") < 0)
|
2015-09-20 14:26:26 -07:00
|
|
|
{
|
|
|
|
ERR(_("ioctl() on pty '%s' failed: %s"), pty, strerror(errno));
|
|
|
|
goto err;
|
|
|
|
}
|
2015-02-23 14:32:12 -08:00
|
|
|
# endif
|
2013-09-22 08:10:39 -07:00
|
|
|
|
2015-02-23 14:29:59 -08:00
|
|
|
if (tcgetattr(ty->slavefd, &t) < 0)
|
|
|
|
{
|
|
|
|
ERR("unable to tcgetattr: %s", strerror(errno));
|
|
|
|
goto err;
|
|
|
|
}
|
2014-01-29 13:57:49 -08:00
|
|
|
t.c_cc[VERASE] = (erase_is_del) ? 0x7f : 0x8;
|
|
|
|
#ifdef IUTF8
|
|
|
|
t.c_iflag |= IUTF8;
|
|
|
|
#endif
|
2015-02-17 13:07:42 -08:00
|
|
|
if (tcsetattr(ty->slavefd, TCSANOW, &t) < 0)
|
2015-01-10 12:01:51 -08:00
|
|
|
{
|
|
|
|
ERR("unable to tcsetattr: %s", strerror(errno));
|
|
|
|
goto err;
|
|
|
|
}
|
2013-09-22 08:10:39 -07:00
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
ty->hand_exe_exit = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
|
|
|
|
_cb_exe_exit, ty);
|
2013-08-29 20:14:18 -07:00
|
|
|
if (!ty->hand_exe_exit)
|
|
|
|
{
|
2014-07-22 14:38:03 -07:00
|
|
|
ERR("event handler add failed");
|
2013-08-29 20:14:18 -07:00
|
|
|
goto err;
|
|
|
|
}
|
2016-12-04 14:24:28 -08:00
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
ty->pid = fork();
|
2014-09-14 13:46:22 -07:00
|
|
|
if (ty->pid < 0)
|
|
|
|
{
|
|
|
|
ERR("unable to fork: %s", strerror(errno));
|
|
|
|
goto err;
|
|
|
|
}
|
2012-06-12 03:10:01 -07:00
|
|
|
if (!ty->pid)
|
|
|
|
{
|
2014-01-22 03:31:37 -08:00
|
|
|
char buf[256];
|
2017-02-17 12:57:57 -08:00
|
|
|
int ret;
|
2012-06-12 03:10:01 -07:00
|
|
|
|
2012-08-05 02:38:58 -07:00
|
|
|
if (cd)
|
|
|
|
{
|
2017-02-17 12:57:57 -08:00
|
|
|
ret = chdir(cd);
|
|
|
|
if (ret != 0)
|
2012-08-05 02:38:58 -07:00
|
|
|
{
|
2014-07-22 14:38:03 -07:00
|
|
|
ERR(_("Could not change current directory to '%s': %s"),
|
2014-07-21 14:51:26 -07:00
|
|
|
cd, strerror(errno));
|
2017-02-17 12:57:57 -08:00
|
|
|
cd = getenv("HOME");
|
|
|
|
if (cd)
|
|
|
|
{
|
|
|
|
ret = chdir(cd);
|
|
|
|
if (ret != 0)
|
|
|
|
{
|
|
|
|
ERR(_("Could not change current directory to '%s': %s"),
|
|
|
|
cd, strerror(errno));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ret != 0)
|
|
|
|
{
|
|
|
|
cd = "/";
|
|
|
|
if (chdir(cd) != 0)
|
|
|
|
{
|
|
|
|
ERR(_("Could not change current directory to '%s': %s"),
|
|
|
|
cd, strerror(errno));
|
|
|
|
}
|
|
|
|
}
|
2012-08-05 02:38:58 -07:00
|
|
|
}
|
|
|
|
}
|
2012-06-17 12:13:03 -07:00
|
|
|
|
|
|
|
|
|
|
|
#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
|
|
|
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);
|
2015-09-20 14:26:26 -07:00
|
|
|
|
2012-12-27 03:20:32 -08:00
|
|
|
close(ty->slavefd);
|
2016-12-04 14:21:58 -08:00
|
|
|
close(ty->fd);
|
2015-09-20 14:26:26 -07:00
|
|
|
|
2016-12-04 14:21:58 -08:00
|
|
|
/* Unset env variables that no longer apply */
|
|
|
|
unsetenv("TERMCAP");
|
|
|
|
unsetenv("COLUMNS");
|
|
|
|
unsetenv("LINES");
|
2012-06-17 11:28:19 -07:00
|
|
|
|
2013-06-16 13:32:50 -07:00
|
|
|
/* pretend to be xterm */
|
|
|
|
if (xterm_256color)
|
|
|
|
{
|
|
|
|
putenv("TERM=xterm-256color");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
putenv("TERM=xterm");
|
|
|
|
}
|
2012-07-23 19:16:21 -07:00
|
|
|
putenv("XTERM_256_COLORS=1");
|
2014-01-22 03:31:37 -08:00
|
|
|
if (emotion_mod)
|
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf), "EMOTION_ENGINE=%s", emotion_mod);
|
|
|
|
putenv(buf);
|
|
|
|
}
|
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
|
|
|
}
|
2016-12-04 14:24:28 -08:00
|
|
|
close(ty->slavefd);
|
|
|
|
ty->slavefd = -1;
|
|
|
|
|
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);
|
2016-12-04 14:24:28 -08:00
|
|
|
/* ensure we're not missing a read */
|
|
|
|
_cb_fd_read(ty, ty->hand_fd);
|
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
_pty_size(ty);
|
2013-05-03 19:44:20 -07:00
|
|
|
termpty_save_register(ty);
|
2012-06-12 03:10:01 -07:00
|
|
|
return ty;
|
|
|
|
err:
|
2015-03-18 07:23:39 -07:00
|
|
|
free(ty->screen);
|
|
|
|
free(ty->screen2);
|
2012-06-12 03:10:01 -07:00
|
|
|
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;
|
2013-05-03 19:44:20 -07:00
|
|
|
|
|
|
|
termpty_save_unregister(ty);
|
2013-01-28 16:43:13 -08:00
|
|
|
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);
|
2013-04-20 00:54:11 -07:00
|
|
|
if (ty->block.chid_map) eina_hash_free(ty->block.chid_map);
|
2013-01-28 08:06:26 -08:00
|
|
|
if (ty->block.active) eina_list_free(ty->block.active);
|
2016-12-05 13:45:44 -08:00
|
|
|
if (ty->fd >= 0)
|
|
|
|
{
|
|
|
|
close(ty->fd);
|
|
|
|
ty->fd = -1;
|
|
|
|
}
|
2012-08-05 21:11:14 -07:00
|
|
|
if (ty->slavefd >= 0) close(ty->slavefd);
|
2012-08-05 18:13:20 -07:00
|
|
|
if (ty->pid >= 0)
|
|
|
|
{
|
|
|
|
int i;
|
2014-09-28 04:45:15 -07:00
|
|
|
|
2012-08-05 18:13:20 -07:00
|
|
|
// in case someone stopped the child - cont it
|
|
|
|
kill(ty->pid, SIGCONT);
|
2014-09-28 04:45:15 -07:00
|
|
|
// sighup the shell
|
|
|
|
kill(ty->pid, SIGHUP);
|
2012-08-05 18:13:20 -07:00
|
|
|
// 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)
|
|
|
|
{
|
2015-08-01 09:37:35 -07:00
|
|
|
size_t i;
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2015-04-06 09:08:23 -07:00
|
|
|
for (i = 0; i < ty->backsize; i++)
|
|
|
|
termpty_save_free(&ty->back[i]);
|
2012-06-12 03:10:01 -07:00
|
|
|
free(ty->back);
|
|
|
|
}
|
2015-03-18 07:23:39 -07:00
|
|
|
free(ty->screen);
|
|
|
|
free(ty->screen2);
|
|
|
|
free(ty->buf);
|
2016-12-18 09:48:03 -08:00
|
|
|
free(ty->tabs);
|
2012-06-12 03:10:01 -07:00
|
|
|
free(ty);
|
|
|
|
}
|
|
|
|
|
2015-04-06 09:08:23 -07:00
|
|
|
static Eina_Bool
|
2015-09-10 14:38:21 -07:00
|
|
|
_termpty_cell_is_empty(const Termcell *cell)
|
2015-04-06 09:08:23 -07:00
|
|
|
{
|
2015-09-10 14:38:21 -07:00
|
|
|
if ((cell->codepoint != 0) &&
|
|
|
|
(!cell->att.invisible) &&
|
|
|
|
(cell->att.fg != COL_INVIS))
|
|
|
|
{
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_termpty_line_is_empty(const Termcell *cells, ssize_t nb_cells)
|
|
|
|
{
|
|
|
|
ssize_t len;
|
2015-04-06 09:08:23 -07:00
|
|
|
|
|
|
|
for (len = nb_cells - 1; len >= 0; len--)
|
|
|
|
{
|
|
|
|
const Termcell *cell = cells + len;
|
|
|
|
|
2015-09-10 14:38:21 -07:00
|
|
|
if (!_termpty_cell_is_empty(cell))
|
2015-04-06 09:08:23 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-18 10:29:39 -08:00
|
|
|
ssize_t
|
|
|
|
termpty_line_length(const Termcell *cells, ssize_t nb_cells)
|
|
|
|
{
|
|
|
|
ssize_t len = nb_cells;
|
|
|
|
|
2016-01-31 01:01:44 -08:00
|
|
|
if (!cells)
|
|
|
|
return 0;
|
|
|
|
|
2015-01-18 10:29:39 -08:00
|
|
|
for (len = nb_cells - 1; len >= 0; len--)
|
|
|
|
{
|
|
|
|
const Termcell *cell = cells + len;
|
|
|
|
|
2015-09-10 14:38:21 -07:00
|
|
|
if (!_termpty_cell_is_empty(cell))
|
2015-01-18 10:29:39 -08:00
|
|
|
return len + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-06 09:08:23 -07:00
|
|
|
#define BACKLOG_ROW_GET(Ty, Y) \
|
2015-06-28 14:37:04 -07:00
|
|
|
(&Ty->back[(Ty->backsize + ty->backpos - ((Y) - 1 )) % Ty->backsize])
|
|
|
|
|
|
|
|
|
2016-11-30 14:25:33 -08:00
|
|
|
static inline void
|
2017-07-06 11:55:02 -07:00
|
|
|
verify_beacon(const Termpty *ty EINA_UNUSED, int verbose EINA_UNUSED)
|
2015-06-28 14:37:04 -07:00
|
|
|
{
|
2016-11-30 14:25:33 -08:00
|
|
|
#if 0
|
2015-06-28 14:37:04 -07:00
|
|
|
Termsave *ts;
|
|
|
|
int nb_lines;
|
|
|
|
int backlog_y = ty->backlog_beacon.backlog_y;
|
|
|
|
int screen_y = ty->backlog_beacon.screen_y;
|
|
|
|
|
|
|
|
assert(ty->backlog_beacon.screen_y >= 0);
|
|
|
|
assert(ty->backlog_beacon.backlog_y >= 0);
|
|
|
|
assert(ty->backlog_beacon.screen_y >= ty->backlog_beacon.backlog_y);
|
|
|
|
|
2016-11-30 14:25:33 -08:00
|
|
|
if (verbose)
|
|
|
|
{
|
|
|
|
ERR("FROM screen_y:%d backlog_y:%d",
|
|
|
|
screen_y, backlog_y);
|
|
|
|
}
|
2015-06-28 14:37:04 -07:00
|
|
|
while (backlog_y > 0)
|
|
|
|
{
|
|
|
|
ts = BACKLOG_ROW_GET(ty, backlog_y);
|
|
|
|
if (!ts->cells)
|
|
|
|
{
|
2016-11-30 14:25:33 -08:00
|
|
|
if (verbose)
|
|
|
|
{
|
|
|
|
ERR("went too far: screen_y:%d backlog_y:%d",
|
|
|
|
screen_y, backlog_y);
|
|
|
|
}
|
2015-06-28 14:37:04 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nb_lines = (ts->w == 0) ? 1 : (ts->w + ty->w - 1) / ty->w;
|
|
|
|
screen_y -= nb_lines;
|
|
|
|
backlog_y--;
|
2016-11-30 14:25:33 -08:00
|
|
|
if (verbose)
|
|
|
|
{
|
|
|
|
ERR("nb_lines:%d screen_y:%d backlog_y:%d ts->w:%d ty->w:%d",
|
|
|
|
nb_lines, screen_y, backlog_y, ts->w, ty->w);
|
|
|
|
}
|
2015-06-28 14:37:04 -07:00
|
|
|
assert(screen_y >= backlog_y);
|
|
|
|
|
|
|
|
}
|
2016-11-30 14:25:33 -08:00
|
|
|
if (verbose)
|
|
|
|
{
|
|
|
|
ERR("TO screen_y:%d backlog_y:%d",
|
|
|
|
screen_y, backlog_y);
|
|
|
|
}
|
2015-06-28 14:37:04 -07:00
|
|
|
assert (backlog_y == 0);
|
|
|
|
assert (screen_y == 0);
|
|
|
|
#endif
|
2016-11-30 14:25:33 -08:00
|
|
|
}
|
2015-06-28 14:37:04 -07:00
|
|
|
|
2015-12-10 12:15:17 -08:00
|
|
|
static void
|
|
|
|
_backlog_remove_latest_nolock(Termpty *ty)
|
|
|
|
{
|
|
|
|
Termsave *ts;
|
|
|
|
if (ty->backsize <= 0)
|
|
|
|
return;
|
|
|
|
ts = BACKLOG_ROW_GET(ty, 1);
|
|
|
|
|
|
|
|
if (ty->backpos == 0)
|
|
|
|
ty->backpos = ty->backsize - 1;
|
|
|
|
else
|
|
|
|
ty->backpos--;
|
|
|
|
|
|
|
|
/* reset beacon */
|
|
|
|
ty->backlog_beacon.screen_y = 0;
|
|
|
|
ty->backlog_beacon.backlog_y = 0;
|
2016-12-05 13:13:30 -08:00
|
|
|
verify_beacon(ty, 0);
|
2015-12-10 12:15:17 -08:00
|
|
|
|
|
|
|
termpty_save_free(ts);
|
|
|
|
}
|
|
|
|
|
2015-04-06 09:08:23 -07:00
|
|
|
|
|
|
|
void
|
|
|
|
termpty_text_save_top(Termpty *ty, Termcell *cells, ssize_t w_max)
|
|
|
|
{
|
|
|
|
Termsave *ts;
|
2017-08-26 09:51:22 -07:00
|
|
|
ssize_t w, i;
|
2015-04-06 09:08:23 -07:00
|
|
|
|
|
|
|
if (ty->backsize <= 0)
|
|
|
|
return;
|
|
|
|
assert(ty->back);
|
|
|
|
|
2016-11-30 14:25:33 -08:00
|
|
|
verify_beacon(ty, 0);
|
2015-08-01 09:37:35 -07:00
|
|
|
termpty_backlog_lock();
|
2015-04-06 09:08:23 -07:00
|
|
|
|
|
|
|
w = termpty_line_length(cells, w_max);
|
2017-08-26 09:51:22 -07:00
|
|
|
for (i = 0; i < w - 1; i++)
|
|
|
|
{
|
|
|
|
cells[i].att.autowrapped = 1;
|
|
|
|
}
|
2015-04-06 09:08:23 -07:00
|
|
|
if (ty->backsize >= 1)
|
|
|
|
{
|
2015-06-28 14:37:04 -07:00
|
|
|
ts = BACKLOG_ROW_GET(ty, 1);
|
2015-04-06 09:08:23 -07:00
|
|
|
if (!ts->cells)
|
|
|
|
goto add_new_ts;
|
|
|
|
/* TODO: RESIZE uncompress ? */
|
|
|
|
if (ts->w && ts->cells[ts->w - 1].att.autowrapped)
|
|
|
|
{
|
2015-06-28 14:37:04 -07:00
|
|
|
int old_len = ts->w;
|
2015-04-06 09:08:23 -07:00
|
|
|
termpty_save_expand(ts, cells, w);
|
2015-06-28 14:37:04 -07:00
|
|
|
ty->backlog_beacon.screen_y += (ts->w + ty->w - 1) / ty->w
|
|
|
|
- (old_len + ty->w - 1) / ty->w;
|
2016-11-30 14:25:33 -08:00
|
|
|
verify_beacon(ty, 0);
|
2015-04-06 09:08:23 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
add_new_ts:
|
2015-06-28 14:37:04 -07:00
|
|
|
ts = BACKLOG_ROW_GET(ty, 0);
|
2015-04-06 09:08:23 -07:00
|
|
|
ts = termpty_save_new(ts, w);
|
|
|
|
if (!ts)
|
|
|
|
return;
|
|
|
|
termpty_cell_copy(ty, cells, ts->cells, w);
|
|
|
|
ty->backpos++;
|
|
|
|
if (ty->backpos >= ty->backsize)
|
|
|
|
ty->backpos = 0;
|
2015-08-01 09:37:35 -07:00
|
|
|
termpty_backlog_unlock();
|
2015-06-28 14:37:04 -07:00
|
|
|
|
|
|
|
ty->backlog_beacon.screen_y++;
|
|
|
|
ty->backlog_beacon.backlog_y++;
|
2015-08-01 09:37:35 -07:00
|
|
|
if (ty->backlog_beacon.backlog_y >= (int)ty->backsize)
|
2015-06-28 14:37:04 -07:00
|
|
|
{
|
|
|
|
ty->backlog_beacon.screen_y = 0;
|
|
|
|
ty->backlog_beacon.backlog_y = 0;
|
|
|
|
}
|
2016-11-30 14:25:33 -08:00
|
|
|
verify_beacon(ty, 0);
|
2015-04-06 09:08:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-18 10:29:39 -08:00
|
|
|
ssize_t
|
|
|
|
termpty_row_length(Termpty *ty, int y)
|
|
|
|
{
|
2015-08-09 05:10:12 -07:00
|
|
|
ssize_t wret;
|
|
|
|
Termcell *cells = termpty_cellrow_get(ty, y, &wret);
|
2015-01-18 10:29:39 -08:00
|
|
|
|
2016-01-31 07:01:00 -08:00
|
|
|
if (!cells)
|
2016-01-31 01:01:44 -08:00
|
|
|
return 0;
|
2015-01-18 10:29:39 -08:00
|
|
|
if (y >= 0)
|
2015-08-09 05:10:12 -07:00
|
|
|
return termpty_line_length(cells, ty->w);
|
2016-01-31 01:01:44 -08:00
|
|
|
return wret;
|
2015-01-18 10:29:39 -08:00
|
|
|
}
|
|
|
|
|
2015-06-28 14:37:04 -07:00
|
|
|
ssize_t
|
2015-08-01 09:37:35 -07:00
|
|
|
termpty_backlog_length(Termpty *ty)
|
2015-06-28 14:37:04 -07:00
|
|
|
{
|
|
|
|
int backlog_y = ty->backlog_beacon.backlog_y;
|
|
|
|
int screen_y = ty->backlog_beacon.screen_y;
|
|
|
|
|
|
|
|
if (!ty->backsize)
|
|
|
|
return 0;
|
2016-12-05 13:13:30 -08:00
|
|
|
verify_beacon(ty, 0);
|
2015-06-28 14:37:04 -07:00
|
|
|
|
2016-11-30 14:25:33 -08:00
|
|
|
backlog_y++;
|
2015-06-28 14:37:04 -07:00
|
|
|
while (42)
|
|
|
|
{
|
|
|
|
int nb_lines;
|
2017-07-06 11:55:02 -07:00
|
|
|
const Termsave *ts;
|
2015-06-28 14:37:04 -07:00
|
|
|
|
|
|
|
ts = BACKLOG_ROW_GET(ty, backlog_y);
|
2015-08-01 09:37:35 -07:00
|
|
|
if (!ts->cells || backlog_y >= (int)ty->backsize)
|
2015-06-28 14:37:04 -07:00
|
|
|
return ty->backlog_beacon.screen_y;
|
|
|
|
|
|
|
|
nb_lines = (ts->w == 0) ? 1 : (ts->w + ty->w - 1) / ty->w;
|
2016-11-30 14:25:33 -08:00
|
|
|
screen_y += nb_lines;
|
2015-06-28 14:37:04 -07:00
|
|
|
ty->backlog_beacon.screen_y = screen_y;
|
|
|
|
ty->backlog_beacon.backlog_y = backlog_y;
|
2016-12-05 13:13:30 -08:00
|
|
|
verify_beacon(ty, 0);
|
2015-06-28 14:37:04 -07:00
|
|
|
backlog_y++;
|
|
|
|
}
|
|
|
|
}
|
2015-04-06 09:08:23 -07:00
|
|
|
|
|
|
|
void
|
|
|
|
termpty_backscroll_adjust(Termpty *ty, int *scroll)
|
|
|
|
{
|
2015-06-28 14:37:04 -07:00
|
|
|
int backlog_y = ty->backlog_beacon.backlog_y;
|
|
|
|
int screen_y = ty->backlog_beacon.screen_y;
|
2015-04-06 09:08:23 -07:00
|
|
|
|
2016-12-05 13:13:30 -08:00
|
|
|
verify_beacon(ty, 0);
|
2015-04-06 09:08:23 -07:00
|
|
|
if (!ty->backsize || *scroll <= 0)
|
|
|
|
{
|
|
|
|
*scroll = 0;
|
|
|
|
return;
|
|
|
|
}
|
2015-06-28 14:37:04 -07:00
|
|
|
if (*scroll < screen_y)
|
2016-11-30 14:25:33 -08:00
|
|
|
{
|
2016-12-05 13:13:30 -08:00
|
|
|
verify_beacon(ty, 0);
|
2016-11-30 14:25:33 -08:00
|
|
|
return;
|
|
|
|
}
|
2015-06-28 14:37:04 -07:00
|
|
|
|
2016-11-30 14:25:33 -08:00
|
|
|
backlog_y++;
|
2015-06-28 14:37:04 -07:00
|
|
|
while (42)
|
2015-04-06 09:08:23 -07:00
|
|
|
{
|
|
|
|
int nb_lines;
|
2015-06-28 14:37:04 -07:00
|
|
|
Termsave *ts;
|
2015-04-06 09:08:23 -07:00
|
|
|
|
2015-06-28 14:37:04 -07:00
|
|
|
ts = BACKLOG_ROW_GET(ty, backlog_y);
|
2015-08-01 09:37:35 -07:00
|
|
|
if (!ts->cells || backlog_y >= (int)ty->backsize)
|
2015-06-28 14:37:04 -07:00
|
|
|
{
|
|
|
|
*scroll = ty->backlog_beacon.screen_y;
|
2016-12-05 13:13:30 -08:00
|
|
|
verify_beacon(ty, 0);
|
2015-06-28 14:37:04 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
nb_lines = (ts->w == 0) ? 1 : (ts->w + ty->w - 1) / ty->w;
|
2016-11-30 14:25:33 -08:00
|
|
|
screen_y += nb_lines;
|
2015-06-28 14:37:04 -07:00
|
|
|
ty->backlog_beacon.screen_y = screen_y;
|
|
|
|
ty->backlog_beacon.backlog_y = backlog_y;
|
2016-12-05 13:13:30 -08:00
|
|
|
verify_beacon(ty, 0);
|
2015-06-28 14:37:04 -07:00
|
|
|
backlog_y++;
|
2016-11-20 09:23:56 -08:00
|
|
|
if (*scroll <= screen_y)
|
2016-11-30 14:25:33 -08:00
|
|
|
{
|
2016-12-05 13:13:30 -08:00
|
|
|
verify_beacon(ty, 0);
|
2016-11-30 14:25:33 -08:00
|
|
|
return;
|
|
|
|
}
|
2015-04-06 09:08:23 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-26 09:51:22 -07:00
|
|
|
/* @requested_y unit is in visual lines on the screen */
|
2015-06-28 14:37:04 -07:00
|
|
|
static Termcell*
|
2015-08-09 05:10:12 -07:00
|
|
|
_termpty_cellrow_from_beacon_get(Termpty *ty, int requested_y, ssize_t *wret)
|
2012-06-12 03:10:01 -07:00
|
|
|
{
|
2015-06-28 14:37:04 -07:00
|
|
|
int backlog_y = ty->backlog_beacon.backlog_y;
|
|
|
|
int screen_y = ty->backlog_beacon.screen_y;
|
2016-11-20 09:23:56 -08:00
|
|
|
Termsave *ts;
|
|
|
|
int nb_lines;
|
2016-11-30 14:25:33 -08:00
|
|
|
int first_loop = EINA_TRUE;
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2015-06-28 14:37:04 -07:00
|
|
|
requested_y = -requested_y;
|
2015-04-06 09:08:23 -07:00
|
|
|
|
2015-08-10 12:44:05 -07:00
|
|
|
/* check if going from 0,0 is faster than using the beacon */
|
|
|
|
if (screen_y - requested_y > requested_y)
|
|
|
|
{
|
2016-11-20 09:23:56 -08:00
|
|
|
ty->backlog_beacon.backlog_y = 0;
|
|
|
|
ty->backlog_beacon.screen_y = 0;
|
2015-08-10 12:44:05 -07:00
|
|
|
}
|
2016-12-05 13:13:30 -08:00
|
|
|
verify_beacon(ty, 0);
|
2015-04-06 09:08:23 -07:00
|
|
|
|
2016-11-20 09:23:56 -08:00
|
|
|
/* going upward */
|
|
|
|
while (requested_y >= screen_y)
|
|
|
|
{
|
2015-04-06 09:08:23 -07:00
|
|
|
ts = BACKLOG_ROW_GET(ty, backlog_y);
|
2016-11-20 09:23:56 -08:00
|
|
|
if (!ts->cells || backlog_y >= (int)ty->backsize)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-06-28 14:37:04 -07:00
|
|
|
nb_lines = (ts->w == 0) ? 1 : (ts->w + ty->w - 1) / ty->w;
|
2015-04-06 09:08:23 -07:00
|
|
|
|
2016-11-30 14:25:33 -08:00
|
|
|
/* Only update the beacon if working on different line than the one
|
|
|
|
* from the beacon */
|
|
|
|
if (!first_loop)
|
|
|
|
{
|
|
|
|
screen_y += nb_lines;
|
|
|
|
ty->backlog_beacon.screen_y = screen_y;
|
|
|
|
ty->backlog_beacon.backlog_y = backlog_y;
|
|
|
|
verify_beacon(ty, 0);
|
|
|
|
}
|
2016-11-20 09:23:56 -08:00
|
|
|
|
|
|
|
if ((screen_y - nb_lines < requested_y) && (requested_y <= screen_y))
|
2015-04-06 09:08:23 -07:00
|
|
|
{
|
2016-11-20 09:23:56 -08:00
|
|
|
/* found the line */
|
|
|
|
int delta = screen_y - requested_y;
|
2015-04-06 09:08:23 -07:00
|
|
|
*wret = ts->w - delta * ty->w;
|
2017-08-26 09:51:22 -07:00
|
|
|
if (*wret > ty->w)
|
|
|
|
*wret = ty->w;
|
2015-04-06 09:08:23 -07:00
|
|
|
return &ts->cells[delta * ty->w];
|
|
|
|
}
|
2016-11-20 09:23:56 -08:00
|
|
|
backlog_y++;
|
2016-12-05 13:13:54 -08:00
|
|
|
first_loop = EINA_FALSE;
|
2016-11-30 14:25:33 -08:00
|
|
|
}
|
2016-11-20 09:23:56 -08:00
|
|
|
/* else, going downward */
|
|
|
|
while (requested_y <= screen_y)
|
|
|
|
{
|
|
|
|
ts = BACKLOG_ROW_GET(ty, backlog_y);
|
|
|
|
if (!ts->cells)
|
2015-06-28 14:37:04 -07:00
|
|
|
{
|
2016-11-20 09:23:56 -08:00
|
|
|
return NULL;
|
2015-06-28 14:37:04 -07:00
|
|
|
}
|
2016-11-20 09:23:56 -08:00
|
|
|
nb_lines = (ts->w == 0) ? 1 : (ts->w + ty->w - 1) / ty->w;
|
|
|
|
|
|
|
|
ty->backlog_beacon.screen_y = screen_y;
|
|
|
|
ty->backlog_beacon.backlog_y = backlog_y;
|
2016-11-30 14:25:33 -08:00
|
|
|
verify_beacon(ty, 0);
|
2016-11-20 09:23:56 -08:00
|
|
|
|
|
|
|
if ((screen_y - nb_lines < requested_y) && (requested_y <= screen_y))
|
2015-06-28 14:37:04 -07:00
|
|
|
{
|
2016-11-20 09:23:56 -08:00
|
|
|
/* found the line */
|
|
|
|
int delta = screen_y - requested_y;
|
|
|
|
*wret = ts->w - delta * ty->w;
|
2017-08-26 09:51:22 -07:00
|
|
|
if (*wret > ty->w)
|
|
|
|
*wret = ty->w;
|
2016-11-20 09:23:56 -08:00
|
|
|
return &ts->cells[delta * ty->w];
|
2015-06-28 14:37:04 -07:00
|
|
|
}
|
2016-11-20 09:23:56 -08:00
|
|
|
screen_y -= nb_lines;
|
|
|
|
backlog_y--;
|
|
|
|
}
|
2015-06-28 14:37:04 -07:00
|
|
|
|
2015-04-06 09:08:23 -07:00
|
|
|
return NULL;
|
2012-06-12 03:10:01 -07:00
|
|
|
}
|
2015-04-06 09:08:23 -07:00
|
|
|
|
2017-08-26 09:51:22 -07:00
|
|
|
/* @requested_y unit is in visual lines on the screen */
|
2015-06-28 14:37:04 -07:00
|
|
|
Termcell *
|
2015-08-09 05:10:12 -07:00
|
|
|
termpty_cellrow_get(Termpty *ty, int y_requested, ssize_t *wret)
|
2015-06-28 14:37:04 -07:00
|
|
|
{
|
|
|
|
if (y_requested >= 0)
|
|
|
|
{
|
|
|
|
if (y_requested >= ty->h)
|
|
|
|
return NULL;
|
|
|
|
*wret = ty->w;
|
|
|
|
return &(TERMPTY_SCREEN(ty, 0, y_requested));
|
|
|
|
}
|
|
|
|
if (!ty->back)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return _termpty_cellrow_from_beacon_get(ty, y_requested, wret);
|
|
|
|
}
|
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
void
|
|
|
|
termpty_write(Termpty *ty, const char *input, int len)
|
|
|
|
{
|
2015-09-20 14:26:26 -07:00
|
|
|
int fd = ty->fd;
|
|
|
|
|
2015-11-01 09:39:39 -08:00
|
|
|
#ifdef ENABLE_FUZZING
|
2015-11-07 10:09:12 -08:00
|
|
|
fd = ty->fd_dev_null;
|
2015-11-01 09:39:39 -08:00
|
|
|
#endif
|
2015-09-20 14:26:26 -07:00
|
|
|
if (fd < 0) return;
|
|
|
|
if (write(fd, input, len) < 0)
|
2014-07-21 14:51:26 -07:00
|
|
|
ERR(_("Could not write to file descriptor %d: %s"),
|
2015-09-20 14:26:26 -07:00
|
|
|
fd, strerror(errno));
|
2012-06-12 03:10:01 -07:00
|
|
|
}
|
|
|
|
|
2015-04-06 09:08:23 -07:00
|
|
|
struct screen_info
|
2013-03-10 11:05:51 -07:00
|
|
|
{
|
2015-04-06 09:08:23 -07:00
|
|
|
Termcell *screen;
|
|
|
|
int w;
|
|
|
|
int h;
|
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
int cy;
|
|
|
|
int cx;
|
|
|
|
int circular_offset;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define SCREEN_INFO_GET_CELLS(Tsi, X, Y) \
|
|
|
|
Tsi->screen[X + (((Y + Tsi->circular_offset) % Tsi->h) * Tsi->w)]
|
2013-03-10 11:05:51 -07:00
|
|
|
|
2015-04-06 09:08:23 -07:00
|
|
|
static void
|
|
|
|
_check_screen_info(Termpty *ty, struct screen_info *si)
|
|
|
|
{
|
|
|
|
if (si->y >= si->h)
|
2013-03-20 14:50:16 -07:00
|
|
|
{
|
2015-04-06 09:08:23 -07:00
|
|
|
Termcell *cells = &SCREEN_INFO_GET_CELLS(si, 0, 0);
|
|
|
|
|
|
|
|
si->y--;
|
|
|
|
termpty_text_save_top(ty, cells, si->w);
|
|
|
|
termpty_cells_clear(ty, cells, si->w);
|
|
|
|
|
|
|
|
si->circular_offset++;
|
|
|
|
if (si->circular_offset >= si->h)
|
|
|
|
si->circular_offset = 0;
|
|
|
|
|
|
|
|
si->cy--;
|
2013-03-10 11:09:45 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-06 09:08:23 -07:00
|
|
|
static void
|
2015-12-07 13:05:49 -08:00
|
|
|
_termpty_line_rewrap(Termpty *ty, Termcell *src_cells, int len,
|
2015-04-06 09:08:23 -07:00
|
|
|
struct screen_info *si,
|
|
|
|
Eina_Bool set_cursor)
|
2013-03-17 11:49:32 -07:00
|
|
|
{
|
2015-12-07 13:05:49 -08:00
|
|
|
int autowrapped;
|
2013-11-10 06:34:40 -08:00
|
|
|
|
2015-04-06 09:08:23 -07:00
|
|
|
if (len == 0)
|
2013-03-20 14:04:59 -07:00
|
|
|
{
|
2015-04-06 09:08:23 -07:00
|
|
|
if (set_cursor)
|
2013-03-24 13:06:34 -07:00
|
|
|
{
|
2015-04-06 09:08:23 -07:00
|
|
|
si->cy = si->y;
|
|
|
|
si->cx = 0;
|
2013-03-24 13:06:34 -07:00
|
|
|
}
|
2015-04-06 09:08:23 -07:00
|
|
|
si->y++;
|
|
|
|
si->x = 0;
|
|
|
|
_check_screen_info(ty, si);
|
|
|
|
return;
|
|
|
|
}
|
2015-12-07 13:05:49 -08:00
|
|
|
|
|
|
|
autowrapped = src_cells[len-1].att.autowrapped;
|
2015-12-10 12:15:17 -08:00
|
|
|
|
2015-04-06 09:08:23 -07:00
|
|
|
while (len > 0)
|
|
|
|
{
|
|
|
|
int copy_width = MIN(len, si->w - si->x);
|
2015-12-07 13:05:49 -08:00
|
|
|
Termcell *dst_cells = &SCREEN_INFO_GET_CELLS(si, si->x, si->y);
|
2015-04-06 09:08:23 -07:00
|
|
|
|
|
|
|
termpty_cell_copy(ty,
|
2015-12-07 13:05:49 -08:00
|
|
|
/*src*/ src_cells,
|
|
|
|
/*dst*/ dst_cells,
|
2015-04-06 09:08:23 -07:00
|
|
|
copy_width);
|
|
|
|
if (set_cursor)
|
2013-03-25 13:34:52 -07:00
|
|
|
{
|
2015-04-06 09:08:23 -07:00
|
|
|
if (ty->cursor_state.cx <= copy_width)
|
2013-03-25 13:34:52 -07:00
|
|
|
{
|
2015-04-06 09:08:23 -07:00
|
|
|
si->cx = ty->cursor_state.cx;
|
|
|
|
si->cy = si->y;
|
2014-12-07 14:51:23 -08:00
|
|
|
}
|
2015-04-06 09:08:23 -07:00
|
|
|
else
|
2014-12-07 14:51:23 -08:00
|
|
|
{
|
2015-04-06 09:08:23 -07:00
|
|
|
ty->cursor_state.cx -= copy_width;
|
2013-03-25 13:34:52 -07:00
|
|
|
}
|
|
|
|
}
|
2015-04-06 09:08:23 -07:00
|
|
|
len -= copy_width;
|
|
|
|
si->x += copy_width;
|
2015-12-07 13:05:49 -08:00
|
|
|
src_cells += copy_width;
|
2015-04-06 09:08:23 -07:00
|
|
|
if (si->x >= si->w)
|
|
|
|
{
|
2015-12-10 12:15:17 -08:00
|
|
|
if ((len > 0) || (len == 0 && autowrapped))
|
|
|
|
{
|
|
|
|
dst_cells = &SCREEN_INFO_GET_CELLS(si, 0, si->y);
|
|
|
|
dst_cells[si->w - 1].att.autowrapped = 1;
|
|
|
|
}
|
2015-04-06 09:08:23 -07:00
|
|
|
si->y++;
|
|
|
|
si->x = 0;
|
|
|
|
}
|
|
|
|
_check_screen_info(ty, si);
|
|
|
|
}
|
2015-09-13 14:15:07 -07:00
|
|
|
if (!autowrapped && si->x != 0)
|
2015-04-06 09:08:23 -07:00
|
|
|
{
|
|
|
|
si->y++;
|
|
|
|
si->x = 0;
|
|
|
|
_check_screen_info(ty, si);
|
2013-03-25 13:34:52 -07:00
|
|
|
}
|
2013-03-10 11:09:45 -07:00
|
|
|
}
|
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
void
|
2013-12-01 10:43:52 -08:00
|
|
|
termpty_resize(Termpty *ty, int new_w, int new_h)
|
2012-06-12 03:10:01 -07:00
|
|
|
{
|
2014-09-14 05:11:14 -07:00
|
|
|
Termcell *new_screen = NULL;
|
2015-04-06 09:08:23 -07:00
|
|
|
int old_y = 0,
|
|
|
|
old_w = ty->w,
|
|
|
|
old_h = ty->h,
|
|
|
|
effective_old_h;
|
|
|
|
int altbuf = 0;
|
|
|
|
struct screen_info new_si = {.screen = NULL};
|
2013-12-01 10:43:52 -08:00
|
|
|
if ((ty->w == new_w) && (ty->h == new_h)) return;
|
2013-03-29 13:42:37 -07:00
|
|
|
|
2015-09-10 14:38:59 -07:00
|
|
|
termpty_backlog_lock();
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2013-12-01 10:43:52 -08:00
|
|
|
if (ty->altbuf)
|
|
|
|
{
|
|
|
|
termpty_screen_swap(ty);
|
2013-12-10 12:21:32 -08:00
|
|
|
altbuf = 1;
|
2013-12-01 10:43:52 -08:00
|
|
|
}
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2013-12-01 10:43:52 -08:00
|
|
|
new_screen = calloc(1, sizeof(Termcell) * new_w * new_h);
|
2014-03-24 05:35:08 -07:00
|
|
|
if (!new_screen)
|
2014-09-14 05:11:14 -07:00
|
|
|
goto bad;
|
2013-12-01 10:43:52 -08:00
|
|
|
free(ty->screen2);
|
|
|
|
ty->screen2 = calloc(1, sizeof(Termcell) * new_w * new_h);
|
2012-06-12 03:10:01 -07:00
|
|
|
if (!ty->screen2)
|
2014-09-14 05:11:14 -07:00
|
|
|
goto bad;
|
2012-06-12 17:26:00 -07:00
|
|
|
|
2015-04-06 09:08:23 -07:00
|
|
|
new_si.screen = new_screen;
|
|
|
|
new_si.w = new_w;
|
|
|
|
new_si.h = new_h;
|
|
|
|
|
|
|
|
/* compute the effective height on the old screen */
|
2015-09-10 14:38:21 -07:00
|
|
|
effective_old_h = 0;
|
2015-04-06 09:08:23 -07:00
|
|
|
for (old_y = old_h -1; old_y >= 0; old_y--)
|
2013-03-23 13:37:03 -07:00
|
|
|
{
|
2015-09-10 14:38:21 -07:00
|
|
|
Termcell *cells = &(TERMPTY_SCREEN(ty, 0, old_y));
|
|
|
|
if (!_termpty_line_is_empty(cells, old_w))
|
2015-04-06 09:08:23 -07:00
|
|
|
{
|
|
|
|
effective_old_h = old_y + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-16 15:05:15 -07:00
|
|
|
termpty_resize_tabs(ty, old_w, new_w);
|
2016-12-18 09:48:03 -08:00
|
|
|
|
2015-09-10 14:38:21 -07:00
|
|
|
if (effective_old_h <= ty->cursor_state.cy)
|
|
|
|
effective_old_h = ty->cursor_state.cy + 1;
|
|
|
|
|
2015-12-10 12:15:17 -08:00
|
|
|
old_y = 0;
|
|
|
|
/* Rewrap the first line from the history if needed */
|
|
|
|
if (ty->backsize >= 1)
|
|
|
|
{
|
|
|
|
Termsave *ts;
|
|
|
|
ts = BACKLOG_ROW_GET(ty, 1);
|
|
|
|
ts = termpty_save_extract(ts);
|
|
|
|
if (ts->cells && ts->w && ts->cells[ts->w - 1].att.autowrapped)
|
|
|
|
{
|
|
|
|
Termcell *cells = &(TERMPTY_SCREEN(ty, 0, old_y)),
|
|
|
|
*new_cells;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
len = termpty_line_length(cells, old_w);
|
|
|
|
|
|
|
|
new_cells = malloc((ts->w + len) * sizeof(Termcell));
|
|
|
|
if (!new_cells)
|
|
|
|
goto bad;
|
|
|
|
memcpy(new_cells, ts->cells, ts->w * sizeof(Termcell));
|
|
|
|
memcpy(new_cells + ts->w, cells, len * sizeof(Termcell));
|
|
|
|
|
|
|
|
len+= ts->w;
|
|
|
|
|
|
|
|
_backlog_remove_latest_nolock(ty);
|
|
|
|
|
|
|
|
_termpty_line_rewrap(ty, new_cells, len, &new_si,
|
|
|
|
old_y == ty->cursor_state.cy);
|
|
|
|
|
|
|
|
free(new_cells);
|
|
|
|
old_y = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* For all the other lines, do not care about the history */
|
2015-12-26 02:52:31 -08:00
|
|
|
for (; old_y < effective_old_h; old_y++)
|
2015-04-06 09:08:23 -07:00
|
|
|
{
|
|
|
|
/* for each line in the old screen, append it to the new screen */
|
2015-09-10 14:38:21 -07:00
|
|
|
Termcell *cells = &(TERMPTY_SCREEN(ty, 0, old_y));
|
2015-04-06 09:08:23 -07:00
|
|
|
int len;
|
|
|
|
|
|
|
|
len = termpty_line_length(cells, old_w);
|
|
|
|
_termpty_line_rewrap(ty, cells, len, &new_si,
|
|
|
|
old_y == ty->cursor_state.cy);
|
2013-03-23 13:37:03 -07:00
|
|
|
}
|
|
|
|
|
2013-12-01 10:43:52 -08:00
|
|
|
free(ty->screen);
|
2014-09-14 05:11:14 -07:00
|
|
|
ty->screen = new_screen;
|
2015-04-06 09:08:23 -07:00
|
|
|
|
|
|
|
ty->cursor_state.cy = (new_si.cy >= 0) ? new_si.cy : 0;
|
|
|
|
ty->cursor_state.cx = (new_si.cx >= 0) ? new_si.cx : 0;
|
|
|
|
ty->circular_offset = new_si.circular_offset;
|
2013-03-10 11:09:45 -07:00
|
|
|
|
2013-12-01 10:43:52 -08:00
|
|
|
ty->w = new_w;
|
|
|
|
ty->h = new_h;
|
2015-04-06 09:08:23 -07:00
|
|
|
ty->termstate.wrapnext = 0;
|
2014-12-07 14:51:23 -08:00
|
|
|
|
2015-06-02 13:48:50 -07:00
|
|
|
if (altbuf)
|
|
|
|
termpty_screen_swap(ty);
|
|
|
|
|
2015-04-19 10:59:29 -07:00
|
|
|
_limit_coord(ty);
|
2013-04-05 13:12:58 -07:00
|
|
|
|
2012-06-12 03:10:01 -07:00
|
|
|
_pty_size(ty);
|
2013-12-01 10:43:52 -08:00
|
|
|
|
2015-08-01 09:37:35 -07:00
|
|
|
termpty_backlog_unlock();
|
2015-06-28 14:37:04 -07:00
|
|
|
|
2016-11-20 09:23:56 -08:00
|
|
|
ty->backlog_beacon.backlog_y = 0;
|
|
|
|
ty->backlog_beacon.screen_y = 0;
|
2015-06-28 14:37:04 -07:00
|
|
|
|
2016-12-05 13:13:30 -08:00
|
|
|
verify_beacon(ty, 0);
|
2014-09-14 05:11:14 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
bad:
|
2015-08-01 09:37:35 -07:00
|
|
|
termpty_backlog_unlock();
|
2014-09-14 05:11:14 -07:00
|
|
|
free(new_screen);
|
2012-06-12 03:10:01 -07:00
|
|
|
}
|
2012-06-16 10:31:54 -07:00
|
|
|
|
|
|
|
void
|
2015-08-01 09:37:35 -07:00
|
|
|
termpty_backlog_size_set(Termpty *ty, size_t size)
|
2012-06-16 10:31:54 -07:00
|
|
|
{
|
2015-04-06 09:08:23 -07:00
|
|
|
if (ty->backsize == size)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* TODO: RESIZE: handle that case better: changing backscroll size */
|
2015-08-01 09:37:35 -07:00
|
|
|
termpty_backlog_lock();
|
2012-06-16 10:31:54 -07:00
|
|
|
|
|
|
|
if (ty->back)
|
|
|
|
{
|
2015-08-01 09:37:35 -07:00
|
|
|
size_t i;
|
|
|
|
|
2015-04-06 09:08:23 -07:00
|
|
|
for (i = 0; i < ty->backsize; i++)
|
|
|
|
termpty_save_free(&ty->back[i]);
|
2012-06-16 10:31:54 -07:00
|
|
|
free(ty->back);
|
|
|
|
}
|
2012-06-18 04:18:46 -07:00
|
|
|
if (size > 0)
|
2015-04-06 09:08:23 -07:00
|
|
|
ty->back = calloc(1, sizeof(Termsave) * size);
|
2012-06-18 04:18:46 -07:00
|
|
|
else
|
|
|
|
ty->back = NULL;
|
2012-06-16 10:31:54 -07:00
|
|
|
ty->backpos = 0;
|
2015-04-06 09:08:23 -07:00
|
|
|
ty->backsize = size;
|
2015-08-01 09:37:35 -07:00
|
|
|
termpty_backlog_unlock();
|
2012-06-16 10:31:54 -07:00
|
|
|
}
|
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)
|
|
|
|
{
|
2013-04-19 18:37:05 -07:00
|
|
|
char *s;
|
2013-01-28 08:06:26 -08:00
|
|
|
if (tb->path) eina_stringshare_del(tb->path);
|
2013-03-11 00:56:07 -07:00
|
|
|
if (tb->link) eina_stringshare_del(tb->link);
|
2013-04-19 18:37:05 -07:00
|
|
|
if (tb->chid) eina_stringshare_del(tb->chid);
|
2013-01-28 08:06:26 -08:00
|
|
|
if (tb->obj) evas_object_del(tb->obj);
|
2013-04-19 18:37:05 -07:00
|
|
|
EINA_LIST_FREE(tb->cmds, s) free(s);
|
2013-01-28 08:06:26 -08:00
|
|
|
free(tb);
|
|
|
|
}
|
|
|
|
|
|
|
|
Termblock *
|
2013-03-11 00:56:07 -07:00
|
|
|
termpty_block_new(Termpty *ty, int w, int h, const char *path, const char *link)
|
2013-01-28 08:06:26 -08:00
|
|
|
{
|
|
|
|
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;
|
2013-04-20 00:54:11 -07:00
|
|
|
tb->pty = ty;
|
2013-01-28 08:06:26 -08:00
|
|
|
tb->id = id;
|
|
|
|
tb->w = w;
|
|
|
|
tb->h = h;
|
|
|
|
tb->path = eina_stringshare_add(path);
|
2013-03-11 00:56:07 -07:00
|
|
|
if (link) tb->link = eina_stringshare_add(link);
|
2013-01-28 08:06:26 -08:00
|
|
|
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->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
|
2017-07-06 11:55:02 -07:00
|
|
|
termpty_block_id_get(const Termcell *cell, int *x, int *y)
|
2013-01-28 08:06:26 -08:00
|
|
|
{
|
|
|
|
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 *
|
2017-07-06 11:55:02 -07:00
|
|
|
termpty_block_get(const Termpty *ty, int id)
|
2013-01-28 08:06:26 -08:00
|
|
|
{
|
2013-01-29 07:54:47 -08:00
|
|
|
if (!ty->block.blocks) return NULL;
|
2013-01-28 08:06:26 -08:00
|
|
|
return eina_hash_find(ty->block.blocks, &id);
|
|
|
|
}
|
2013-01-29 07:54:47 -08:00
|
|
|
|
2013-04-20 00:54:11 -07:00
|
|
|
void
|
|
|
|
termpty_block_chid_update(Termpty *ty, Termblock *blk)
|
|
|
|
{
|
|
|
|
if (!blk->chid) return;
|
|
|
|
if (!ty->block.chid_map)
|
|
|
|
ty->block.chid_map = eina_hash_string_superfast_new(NULL);
|
|
|
|
if (!ty->block.chid_map) return;
|
|
|
|
eina_hash_add(ty->block.chid_map, blk->chid, blk);
|
|
|
|
}
|
2013-01-29 07:54:47 -08:00
|
|
|
|
2013-04-20 00:54:11 -07:00
|
|
|
Termblock *
|
2017-07-06 11:55:02 -07:00
|
|
|
termpty_block_chid_get(const Termpty *ty, const char *chid)
|
2013-04-20 00:54:11 -07:00
|
|
|
{
|
|
|
|
Termblock *tb;
|
|
|
|
|
|
|
|
tb = eina_hash_find(ty->block.chid_map, chid);
|
|
|
|
return tb;
|
|
|
|
}
|
2013-01-29 07:54:47 -08:00
|
|
|
|
2013-10-28 02:55:19 -07:00
|
|
|
static void
|
|
|
|
_handle_block_codepoint_overwrite_heavy(Termpty *ty, int oldc, int newc)
|
2013-01-29 07:54:47 -08:00
|
|
|
{
|
|
|
|
Termblock *tb;
|
|
|
|
int ido = 0, idn = 0;
|
2013-10-25 07:37:10 -07:00
|
|
|
|
2013-01-29 07:54:47 -08:00
|
|
|
if (oldc & 0x80000000) ido = (oldc >> 18) & 0x1fff;
|
|
|
|
if (newc & 0x80000000) idn = (newc >> 18) & 0x1fff;
|
|
|
|
if (((oldc & 0x80000000) && (newc & 0x80000000)) && (idn == ido)) return;
|
|
|
|
|
|
|
|
if (oldc & 0x80000000)
|
|
|
|
{
|
|
|
|
tb = termpty_block_get(ty, ido);
|
|
|
|
if (!tb) return;
|
|
|
|
tb->refs--;
|
|
|
|
if (tb->refs == 0)
|
|
|
|
{
|
|
|
|
if (tb->active)
|
|
|
|
ty->block.active = eina_list_remove(ty->block.active, tb);
|
|
|
|
eina_hash_del(ty->block.blocks, &ido, tb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newc & 0x80000000)
|
|
|
|
{
|
|
|
|
tb = termpty_block_get(ty, idn);
|
|
|
|
if (!tb) return;
|
|
|
|
tb->refs++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-28 02:55:19 -07:00
|
|
|
/* Try to trick the compiler into inlining the first test */
|
|
|
|
static inline void
|
2014-03-25 13:34:48 -07:00
|
|
|
_handle_block_codepoint_overwrite(Termpty *ty, Eina_Unicode oldc, Eina_Unicode newc)
|
2013-10-28 02:55:19 -07:00
|
|
|
{
|
|
|
|
if (!((oldc | newc) & 0x80000000)) return;
|
|
|
|
_handle_block_codepoint_overwrite_heavy(ty, oldc, newc);
|
|
|
|
}
|
|
|
|
|
2013-01-29 07:54:47 -08:00
|
|
|
void
|
|
|
|
termpty_cell_copy(Termpty *ty, Termcell *src, Termcell *dst, int n)
|
|
|
|
{
|
|
|
|
int i;
|
2015-04-06 09:08:23 -07:00
|
|
|
|
2013-01-29 07:54:47 -08:00
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
_handle_block_codepoint_overwrite(ty, dst[i].codepoint, src[i].codepoint);
|
|
|
|
dst[i] = src[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-11-18 12:41:30 -08:00
|
|
|
termpty_screen_swap(Termpty *ty)
|
2013-01-29 07:54:47 -08:00
|
|
|
{
|
2013-12-01 10:43:52 -08:00
|
|
|
Termcell *tmp_screen;
|
|
|
|
int tmp_circular_offset;
|
|
|
|
|
|
|
|
tmp_screen = ty->screen;
|
|
|
|
ty->screen = ty->screen2;
|
|
|
|
ty->screen2 = tmp_screen;
|
|
|
|
|
|
|
|
tmp_circular_offset = ty->circular_offset;
|
|
|
|
ty->circular_offset = ty->circular_offset2;
|
|
|
|
ty->circular_offset2 = tmp_circular_offset;
|
2013-11-18 12:41:30 -08:00
|
|
|
|
|
|
|
ty->altbuf = !ty->altbuf;
|
|
|
|
|
|
|
|
if (ty->cb.cancel_sel.func)
|
|
|
|
ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
|
2013-01-29 07:54:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
termpty_cell_fill(Termpty *ty, Termcell *src, Termcell *dst, int n)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (src)
|
|
|
|
{
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
_handle_block_codepoint_overwrite(ty, dst[i].codepoint, src[0].codepoint);
|
|
|
|
dst[i] = src[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
_handle_block_codepoint_overwrite(ty, dst[i].codepoint, 0);
|
|
|
|
memset(&(dst[i]), 0, sizeof(*dst));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-26 12:58:59 -07:00
|
|
|
void
|
|
|
|
termpty_cells_set_content(Termpty *ty, Termcell *cells,
|
|
|
|
Eina_Unicode codepoint, int count)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
_handle_block_codepoint_overwrite(ty, cells[i].codepoint, codepoint);
|
|
|
|
cells[i].codepoint = codepoint;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-26 14:36:23 -07:00
|
|
|
void
|
|
|
|
termpty_cells_att_fill_preserve_colors(Termpty *ty, Termcell *cells,
|
|
|
|
Eina_Unicode codepoint, int count)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Termcell local = { .codepoint = codepoint, .att = ty->termstate.att};
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
Termatt att = cells[i].att;
|
|
|
|
_handle_block_codepoint_overwrite(ty, cells[i].codepoint, codepoint);
|
|
|
|
cells[i] = local;
|
|
|
|
if (ty->termstate.att.fg == 0 && ty->termstate.att.bg == 0)
|
|
|
|
{
|
|
|
|
cells[i].att.fg = att.fg;
|
|
|
|
cells[i].att.fg256 = att.fg256;
|
|
|
|
cells[i].att.fgintense = att.fgintense;
|
|
|
|
|
|
|
|
cells[i].att.bg = att.bg;
|
|
|
|
cells[i].att.bg256 = att.bg256;
|
|
|
|
cells[i].att.bgintense = att.bgintense;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-26 12:58:59 -07:00
|
|
|
|
2013-01-29 07:54:47 -08:00
|
|
|
void
|
2014-03-25 13:34:48 -07:00
|
|
|
termpty_cell_codepoint_att_fill(Termpty *ty, Eina_Unicode codepoint,
|
|
|
|
Termatt att, Termcell *dst, int n)
|
2013-01-29 07:54:47 -08:00
|
|
|
{
|
2014-05-08 04:55:01 -07:00
|
|
|
Termcell local = { .codepoint = codepoint, .att = att };
|
2013-01-29 07:54:47 -08:00
|
|
|
int i;
|
2014-05-08 04:55:01 -07:00
|
|
|
|
2013-01-29 07:54:47 -08:00
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
_handle_block_codepoint_overwrite(ty, dst[i].codepoint, codepoint);
|
2013-10-28 02:55:19 -07:00
|
|
|
dst[i] = local;
|
2013-01-29 07:54:47 -08:00
|
|
|
}
|
|
|
|
}
|
2013-09-22 08:10:39 -07:00
|
|
|
|
|
|
|
Config *
|
|
|
|
termpty_config_get(const Termpty *ty)
|
|
|
|
{
|
|
|
|
return termio_config_get(ty->obj);
|
|
|
|
}
|