Merge 685202bbc4f512e207015944dd8511624ee86a31 into 0fc69a4ca5b359504bd017acecda7843a387aa78
This commit is contained in:
commit
b519c87ded
@ -43,6 +43,9 @@
|
||||
struct kmscon_buffer;
|
||||
struct kmscon_console;
|
||||
|
||||
#define KMSCON_DEFAULT_WIDTH 80
|
||||
#define KMSCON_DEFAULT_HEIGHT 24
|
||||
|
||||
/* console buffer with cell objects */
|
||||
|
||||
int kmscon_buffer_new(struct kmscon_buffer **out, unsigned int x,
|
||||
|
@ -86,8 +86,6 @@
|
||||
#include "log.h"
|
||||
#include "unicode.h"
|
||||
|
||||
#define DEFAULT_WIDTH 80
|
||||
#define DEFAULT_HEIGHT 24
|
||||
#define DEFAULT_SCROLLBACK 128
|
||||
|
||||
struct cell {
|
||||
@ -172,7 +170,7 @@ static int resize_line(struct line *line, unsigned int width)
|
||||
return -EINVAL;
|
||||
|
||||
if (!width)
|
||||
width = DEFAULT_WIDTH;
|
||||
width = KMSCON_DEFAULT_WIDTH;
|
||||
|
||||
if (line->size < width) {
|
||||
tmp = realloc(line->cells, width * sizeof(struct cell));
|
||||
@ -337,9 +335,9 @@ int kmscon_buffer_resize(struct kmscon_buffer *buf, unsigned int x,
|
||||
return -EINVAL;
|
||||
|
||||
if (!x)
|
||||
x = DEFAULT_WIDTH;
|
||||
x = KMSCON_DEFAULT_WIDTH;
|
||||
if (!y)
|
||||
y = DEFAULT_HEIGHT;
|
||||
y = KMSCON_DEFAULT_HEIGHT;
|
||||
|
||||
if (buf->size_x == x && buf->size_y == y)
|
||||
return 0;
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "console.h"
|
||||
#include "eloop.h"
|
||||
#include "font.h"
|
||||
#include "input.h"
|
||||
#include "log.h"
|
||||
#include "terminal.h"
|
||||
#include "unicode.h"
|
||||
@ -59,6 +60,9 @@ struct kmscon_terminal {
|
||||
struct kmscon_console *console;
|
||||
struct kmscon_idle *redraw;
|
||||
struct kmscon_vte *vte;
|
||||
|
||||
kmscon_terminal_closed_cb closed_cb;
|
||||
void *closed_data;
|
||||
};
|
||||
|
||||
static void draw_all(struct kmscon_idle *idle, void *data)
|
||||
@ -101,20 +105,10 @@ static void schedule_redraw(struct kmscon_terminal *term)
|
||||
log_warning("terminal: cannot schedule redraw\n");
|
||||
}
|
||||
|
||||
static const char help_text[] =
|
||||
"terminal subsystem - KMS based console test\n"
|
||||
"This is some default text to test the drawing operations.\n\n";
|
||||
|
||||
static void print_help(struct kmscon_terminal *term)
|
||||
void vte_changed(struct kmscon_vte *vte, void *data)
|
||||
{
|
||||
unsigned int i, len;
|
||||
kmscon_symbol_t ch;
|
||||
|
||||
len = sizeof(help_text) - 1;
|
||||
for (i = 0; i < len; ++i) {
|
||||
ch = kmscon_symbol_make(help_text[i]);
|
||||
kmscon_terminal_input(term, ch);
|
||||
}
|
||||
struct kmscon_terminal *term = data;
|
||||
schedule_redraw(term);
|
||||
}
|
||||
|
||||
int kmscon_terminal_new(struct kmscon_terminal **out,
|
||||
@ -143,11 +137,10 @@ int kmscon_terminal_new(struct kmscon_terminal **out,
|
||||
if (ret)
|
||||
goto err_idle;
|
||||
|
||||
ret = kmscon_vte_new(&term->vte);
|
||||
ret = kmscon_vte_new(&term->vte, vte_changed, term);
|
||||
if (ret)
|
||||
goto err_con;
|
||||
kmscon_vte_bind(term->vte, term->console);
|
||||
print_help(term);
|
||||
|
||||
*out = term;
|
||||
return 0;
|
||||
@ -177,16 +170,16 @@ void kmscon_terminal_unref(struct kmscon_terminal *term)
|
||||
if (--term->ref)
|
||||
return;
|
||||
|
||||
term->closed_cb = NULL;
|
||||
kmscon_terminal_close(term);
|
||||
kmscon_terminal_rm_all_outputs(term);
|
||||
kmscon_vte_unref(term->vte);
|
||||
kmscon_console_unref(term->console);
|
||||
kmscon_terminal_disconnect_eloop(term);
|
||||
free(term);
|
||||
log_debug("terminal: destroying terminal object\n");
|
||||
}
|
||||
|
||||
int kmscon_terminal_connect_eloop(struct kmscon_terminal *term,
|
||||
struct kmscon_eloop *eloop)
|
||||
int connect_eloop(struct kmscon_terminal *term, struct kmscon_eloop *eloop)
|
||||
{
|
||||
if (!term || !eloop)
|
||||
return -EINVAL;
|
||||
@ -200,7 +193,7 @@ int kmscon_terminal_connect_eloop(struct kmscon_terminal *term,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kmscon_terminal_disconnect_eloop(struct kmscon_terminal *term)
|
||||
void disconnect_eloop(struct kmscon_terminal *term)
|
||||
{
|
||||
if (!term)
|
||||
return;
|
||||
@ -209,6 +202,60 @@ void kmscon_terminal_disconnect_eloop(struct kmscon_terminal *term)
|
||||
term->eloop = NULL;
|
||||
}
|
||||
|
||||
static void vte_closed(struct kmscon_vte *vte, void *data)
|
||||
{
|
||||
struct kmscon_terminal *term = data;
|
||||
kmscon_terminal_close(term);
|
||||
}
|
||||
|
||||
int kmscon_terminal_open(struct kmscon_terminal *term,
|
||||
struct kmscon_eloop *eloop,
|
||||
kmscon_terminal_closed_cb closed_cb, void *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!term)
|
||||
return -EINVAL;
|
||||
|
||||
ret = connect_eloop(term, eloop);
|
||||
if (ret == -EALREADY) {
|
||||
disconnect_eloop(term);
|
||||
ret = connect_eloop(term, eloop);
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = kmscon_vte_open(term->vte, eloop, vte_closed, term);
|
||||
if (ret) {
|
||||
disconnect_eloop(term);
|
||||
return ret;
|
||||
}
|
||||
|
||||
term->closed_cb = closed_cb;
|
||||
term->closed_data = data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kmscon_terminal_close(struct kmscon_terminal *term)
|
||||
{
|
||||
kmscon_terminal_closed_cb cb;
|
||||
void *data;
|
||||
|
||||
if (!term)
|
||||
return;
|
||||
|
||||
cb = term->closed_cb;
|
||||
data = term->closed_data;
|
||||
term->closed_data = NULL;
|
||||
term->closed_cb = NULL;
|
||||
|
||||
disconnect_eloop(term);
|
||||
kmscon_vte_close(term->vte);
|
||||
|
||||
if (cb)
|
||||
cb(term, data);
|
||||
}
|
||||
|
||||
int kmscon_terminal_add_output(struct kmscon_terminal *term,
|
||||
struct kmscon_output *output)
|
||||
{
|
||||
@ -239,6 +286,7 @@ int kmscon_terminal_add_output(struct kmscon_terminal *term,
|
||||
if (term->max_height < height) {
|
||||
term->max_height = height;
|
||||
kmscon_console_resize(term->console, 0, 0, term->max_height);
|
||||
kmscon_vte_resize(term->vte);
|
||||
}
|
||||
|
||||
schedule_redraw(term);
|
||||
@ -261,8 +309,8 @@ void kmscon_terminal_rm_all_outputs(struct kmscon_terminal *term)
|
||||
}
|
||||
}
|
||||
|
||||
void kmscon_terminal_input(struct kmscon_terminal *term, kmscon_symbol_t ch)
|
||||
void kmscon_terminal_input(struct kmscon_terminal *term,
|
||||
struct kmscon_input_event *ev)
|
||||
{
|
||||
kmscon_vte_input(term->vte, ch);
|
||||
schedule_redraw(term);
|
||||
kmscon_vte_input(term->vte, ev);
|
||||
}
|
||||
|
@ -41,19 +41,24 @@
|
||||
|
||||
struct kmscon_terminal;
|
||||
|
||||
typedef void (*kmscon_terminal_closed_cb) (struct kmscon_terminal *term,
|
||||
void *data);
|
||||
|
||||
int kmscon_terminal_new(struct kmscon_terminal **out,
|
||||
struct kmscon_font_factory *ff);
|
||||
void kmscon_terminal_ref(struct kmscon_terminal *term);
|
||||
void kmscon_terminal_unref(struct kmscon_terminal *term);
|
||||
|
||||
int kmscon_terminal_connect_eloop(struct kmscon_terminal *term,
|
||||
struct kmscon_eloop *eloop);
|
||||
void kmscon_terminal_disconnect_eloop(struct kmscon_terminal *term);
|
||||
int kmscon_terminal_open(struct kmscon_terminal *term,
|
||||
struct kmscon_eloop *eloop,
|
||||
kmscon_terminal_closed_cb closed_cb, void *data);
|
||||
void kmscon_terminal_close(struct kmscon_terminal *term);
|
||||
|
||||
int kmscon_terminal_add_output(struct kmscon_terminal *term,
|
||||
struct kmscon_output *output);
|
||||
void kmscon_terminal_rm_all_outputs(struct kmscon_terminal *term);
|
||||
|
||||
void kmscon_terminal_input(struct kmscon_terminal *term, kmscon_symbol_t ch);
|
||||
void kmscon_terminal_input(struct kmscon_terminal *term,
|
||||
struct kmscon_input_event *ev);
|
||||
|
||||
#endif /* KMSCON_TERMINAL_H */
|
||||
|
367
src/vte.c
367
src/vte.c
@ -30,11 +30,22 @@
|
||||
* console subsystem as output and is tightly bound to it.
|
||||
*/
|
||||
|
||||
/* for pty functions */
|
||||
#define _XOPEN_SOURCE 700
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <pty.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <X11/keysym.h>
|
||||
|
||||
#include "console.h"
|
||||
#include "eloop.h"
|
||||
#include "input.h"
|
||||
#include "log.h"
|
||||
#include "unicode.h"
|
||||
#include "vte.h"
|
||||
@ -42,9 +53,20 @@
|
||||
struct kmscon_vte {
|
||||
unsigned long ref;
|
||||
struct kmscon_console *con;
|
||||
struct kmscon_eloop *eloop;
|
||||
|
||||
int pty;
|
||||
struct kmscon_fd *pty_fd;
|
||||
|
||||
kmscon_vte_changed_cb changed_cb;
|
||||
void *changed_data;
|
||||
|
||||
kmscon_vte_closed_cb closed_cb;
|
||||
void *closed_data;
|
||||
};
|
||||
|
||||
int kmscon_vte_new(struct kmscon_vte **out)
|
||||
int kmscon_vte_new(struct kmscon_vte **out,
|
||||
kmscon_vte_changed_cb changed_cb, void *data)
|
||||
{
|
||||
struct kmscon_vte *vte;
|
||||
|
||||
@ -58,8 +80,11 @@ int kmscon_vte_new(struct kmscon_vte **out)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(vte, 0, sizeof(*vte));
|
||||
vte->pty = -1;
|
||||
vte->ref = 1;
|
||||
|
||||
vte->changed_cb = changed_cb;
|
||||
vte->changed_data = data;
|
||||
*out = vte;
|
||||
return 0;
|
||||
}
|
||||
@ -81,6 +106,7 @@ void kmscon_vte_unref(struct kmscon_vte *vte)
|
||||
return;
|
||||
|
||||
kmscon_console_unref(vte->con);
|
||||
kmscon_vte_close(vte);
|
||||
free(vte);
|
||||
log_debug("vte: destroying vte object\n");
|
||||
}
|
||||
@ -95,7 +121,37 @@ void kmscon_vte_bind(struct kmscon_vte *vte, struct kmscon_console *con)
|
||||
kmscon_console_ref(vte->con);
|
||||
}
|
||||
|
||||
void kmscon_vte_input(struct kmscon_vte *vte, kmscon_symbol_t ch)
|
||||
/* FIXME: this is just temporary. */
|
||||
void kmscon_vte_input(struct kmscon_vte *vte, struct kmscon_input_event *ev)
|
||||
{
|
||||
kmscon_symbol_t ch;
|
||||
ssize_t len;
|
||||
|
||||
if (!vte || !vte->con || vte->pty < 0)
|
||||
return;
|
||||
|
||||
if (ev->keysym == XK_Return)
|
||||
ch = '\n';
|
||||
else if (ev->unicode == KMSCON_INPUT_INVALID)
|
||||
return;
|
||||
else
|
||||
ch = kmscon_symbol_make(ev->unicode);
|
||||
|
||||
if (ch > 127)
|
||||
return;
|
||||
|
||||
if (ev->mods & KMSCON_CONTROL_MASK)
|
||||
if (iscntrl(toupper(ch) ^ 64))
|
||||
ch = toupper(ch) ^ 64;
|
||||
|
||||
len = write(vte->pty, (char *)&ch, 1);
|
||||
if (len <= 0) {
|
||||
kmscon_vte_close(vte);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void kmscon_vte_putc(struct kmscon_vte *vte, kmscon_symbol_t ch)
|
||||
{
|
||||
if (!vte || !vte->con)
|
||||
return;
|
||||
@ -105,3 +161,310 @@ void kmscon_vte_input(struct kmscon_vte *vte, kmscon_symbol_t ch)
|
||||
else
|
||||
kmscon_console_write(vte->con, ch);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* - Decide which terminal we're emulating and set TERM accordingly.
|
||||
* - Decide what to exec here: login, some getty equivalent, a shell...
|
||||
* - Might also need to update some details in utmp wtmp and friends.
|
||||
*/
|
||||
static void __attribute__((noreturn))
|
||||
exec_child(int pty_master)
|
||||
{
|
||||
const char *sh;
|
||||
|
||||
setenv("TERM", "linux", 1);
|
||||
|
||||
sh = getenv("SHELL") ?: _PATH_BSHELL;
|
||||
execlp(sh, sh, "-i", NULL);
|
||||
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static int fork_pty_child(int master, struct winsize *ws)
|
||||
{
|
||||
int ret, saved_errno;
|
||||
pid_t pid;
|
||||
const char *slave_name;
|
||||
int slave = -1;
|
||||
|
||||
/* This doesn't actually do anything on linux. */
|
||||
ret = grantpt(master);
|
||||
if (ret < 0) {
|
||||
log_err("vte: grantpt failed: %m");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
ret = unlockpt(master);
|
||||
if (ret < 0) {
|
||||
log_err("vte: cannot unlock pty: %m");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
slave_name = ptsname(master);
|
||||
if (!slave_name) {
|
||||
log_err("vte: cannot find pty slave name: %m");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* This also loses our controlling tty. */
|
||||
pid = setsid();
|
||||
if (pid < 0) {
|
||||
log_err("vte: cannot start a new session: %m");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* And the slave pty becomes our controlling tty. */
|
||||
slave = open(slave_name, O_RDWR | O_CLOEXEC);
|
||||
if (slave < 0) {
|
||||
log_err("vte: cannot open pty slave: %m");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (ws) {
|
||||
ret = ioctl(slave, TIOCSWINSZ, ws);
|
||||
if (ret)
|
||||
log_warning("vte: cannot set slave pty "
|
||||
"window size: %m");
|
||||
}
|
||||
|
||||
if (dup2(slave, STDIN_FILENO) != STDIN_FILENO ||
|
||||
dup2(slave, STDOUT_FILENO) != STDOUT_FILENO ||
|
||||
dup2(slave, STDERR_FILENO) != STDERR_FILENO) {
|
||||
log_err("vte: cannot duplicate slave pty: %m");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
close(master);
|
||||
close(slave);
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
saved_errno = errno;
|
||||
if (slave > 0)
|
||||
close(slave);
|
||||
close(master);
|
||||
return -saved_errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is functionally equivalent to forkpty(3). We do it manually to obtain
|
||||
* a little bit more control of the process, and as a bonus avoid linking to
|
||||
* the libutil library in glibc.
|
||||
*/
|
||||
static pid_t fork_pty(int *pty_out, struct winsize *ws)
|
||||
{
|
||||
int ret;
|
||||
pid_t pid;
|
||||
int master;
|
||||
|
||||
master = posix_openpt(O_RDWR | O_NOCTTY | O_CLOEXEC | O_NONBLOCK);
|
||||
if (master < 0) {
|
||||
ret = -errno;
|
||||
log_err("vte: cannot open pty master: %m");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
log_err("vte: failed to fork pty slave: %m");
|
||||
ret = -errno;
|
||||
goto err_master;
|
||||
case 0:
|
||||
ret = fork_pty_child(master, ws);
|
||||
if (ret)
|
||||
goto err_master;
|
||||
*pty_out = -1;
|
||||
return 0;
|
||||
default:
|
||||
*pty_out = master;
|
||||
return pid;
|
||||
}
|
||||
|
||||
err_master:
|
||||
close(master);
|
||||
err_out:
|
||||
*pty_out = -1;
|
||||
errno = -ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int pty_spawn(struct kmscon_vte *vte)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
if (vte->pty >= 0)
|
||||
return -EALREADY;
|
||||
|
||||
struct winsize ws;
|
||||
memset(&ws, 0, sizeof(ws));
|
||||
ws.ws_col = kmscon_console_get_width(vte->con) ?:
|
||||
KMSCON_DEFAULT_WIDTH;
|
||||
ws.ws_row = kmscon_console_get_height(vte->con) ?:
|
||||
KMSCON_DEFAULT_HEIGHT;
|
||||
|
||||
pid = fork_pty(&vte->pty, &ws);
|
||||
switch (pid) {
|
||||
case -1:
|
||||
log_err("vte: cannot fork or open pty pair: %m");
|
||||
return -errno;
|
||||
case 0:
|
||||
exec_child(vte->pty);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pty_input(struct kmscon_fd *fd, int mask, void *data)
|
||||
{
|
||||
int ret, nread;
|
||||
ssize_t len, i;
|
||||
struct kmscon_vte *vte = data;
|
||||
|
||||
if (!vte || vte->pty < 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If we get a hangup or an error, but the pty is still readable, we
|
||||
* read what's left and deal with the rest on the next dispatch.
|
||||
*/
|
||||
if (!(mask & KMSCON_READABLE)) {
|
||||
if (mask & KMSCON_ERR)
|
||||
log_warning("vte: error condition happened on pty\n");
|
||||
kmscon_vte_close(vte);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = ioctl(vte->pty, FIONREAD, &nread);
|
||||
if (ret) {
|
||||
log_warning("vte: cannot peek into pty input buffer: %m");
|
||||
return;
|
||||
} else if (nread <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
char buf[nread];
|
||||
len = read(vte->pty, buf, nread);
|
||||
if (len == -1) {
|
||||
/* EIO is hangup, although we should have caught it above. */
|
||||
if (errno != EIO)
|
||||
log_err("vte: cannot read from pty: %m");
|
||||
kmscon_vte_close(vte);
|
||||
return;
|
||||
} else if (len == 0) {
|
||||
kmscon_vte_close(vte);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i=0; i < len; i++)
|
||||
kmscon_vte_putc(vte, buf[i]);
|
||||
|
||||
if (vte->changed_cb)
|
||||
vte->changed_cb(vte, vte->changed_data);
|
||||
}
|
||||
|
||||
static int connect_eloop(struct kmscon_vte *vte, struct kmscon_eloop *eloop)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (vte->eloop)
|
||||
return -EALREADY;
|
||||
|
||||
ret = kmscon_eloop_new_fd(eloop, &vte->pty_fd, vte->pty,
|
||||
KMSCON_READABLE, pty_input, vte);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
kmscon_eloop_ref(eloop);
|
||||
vte->eloop = eloop;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void disconnect_eloop(struct kmscon_vte *vte)
|
||||
{
|
||||
kmscon_eloop_rm_fd(vte->pty_fd);
|
||||
kmscon_eloop_unref(vte->eloop);
|
||||
vte->pty_fd = NULL;
|
||||
vte->eloop = NULL;
|
||||
}
|
||||
|
||||
int kmscon_vte_open(struct kmscon_vte *vte, struct kmscon_eloop *eloop,
|
||||
kmscon_vte_closed_cb closed_cb, void *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!vte || !eloop)
|
||||
return -EINVAL;
|
||||
|
||||
if (vte->pty >= 0)
|
||||
return -EALREADY;
|
||||
|
||||
ret = pty_spawn(vte);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = connect_eloop(vte, eloop);
|
||||
if (ret == -EALREADY) {
|
||||
disconnect_eloop(vte);
|
||||
ret = connect_eloop(vte, eloop);
|
||||
}
|
||||
if (ret) {
|
||||
close(vte->pty);
|
||||
vte->pty = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
vte->closed_cb = closed_cb;
|
||||
vte->closed_data = data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kmscon_vte_close(struct kmscon_vte *vte)
|
||||
{
|
||||
kmscon_vte_closed_cb cb;
|
||||
void *data;
|
||||
|
||||
if (!vte || vte->pty < 0)
|
||||
return;
|
||||
|
||||
disconnect_eloop(vte);
|
||||
|
||||
close(vte->pty);
|
||||
vte->pty = -1;
|
||||
|
||||
cb = vte->closed_cb;
|
||||
data = vte->closed_data;
|
||||
vte->closed_cb = NULL;
|
||||
vte->closed_data = NULL;
|
||||
|
||||
if (cb)
|
||||
cb(vte, data);
|
||||
}
|
||||
|
||||
void kmscon_vte_resize(struct kmscon_vte *vte)
|
||||
{
|
||||
int ret;
|
||||
struct winsize ws;
|
||||
|
||||
if (!vte || !vte->con || vte->pty < 0)
|
||||
return;
|
||||
|
||||
memset(&ws, 0, sizeof(ws));
|
||||
ws.ws_col = kmscon_console_get_width(vte->con);
|
||||
ws.ws_row = kmscon_console_get_height(vte->con);
|
||||
|
||||
/*
|
||||
* This will send SIGWINCH to the pty slave foreground process group.
|
||||
* We will also get one, but we don't need it.
|
||||
*/
|
||||
ret = ioctl(vte->pty, TIOCSWINSZ, &ws);
|
||||
if (ret) {
|
||||
log_warning("vte: cannot set window size\n");
|
||||
return;
|
||||
}
|
||||
|
||||
log_debug("vte: window size set to %hdx%hd\n", ws.ws_col, ws.ws_row);
|
||||
}
|
||||
|
16
src/vte.h
16
src/vte.h
@ -36,14 +36,26 @@
|
||||
#include <stdlib.h>
|
||||
#include "console.h"
|
||||
#include "unicode.h"
|
||||
#include "eloop.h"
|
||||
|
||||
struct kmscon_vte;
|
||||
|
||||
int kmscon_vte_new(struct kmscon_vte **out);
|
||||
typedef void (*kmscon_vte_changed_cb) (struct kmscon_vte *vte, void *data);
|
||||
typedef void (*kmscon_vte_closed_cb) (struct kmscon_vte *vte, void *data);
|
||||
|
||||
int kmscon_vte_new(struct kmscon_vte **out,
|
||||
kmscon_vte_changed_cb changed_cb, void *data);
|
||||
void kmscon_vte_ref(struct kmscon_vte *vte);
|
||||
void kmscon_vte_unref(struct kmscon_vte *vte);
|
||||
|
||||
int kmscon_vte_open(struct kmscon_vte *vte, struct kmscon_eloop *eloop,
|
||||
kmscon_vte_closed_cb closed_cb, void *data);
|
||||
void kmscon_vte_close(struct kmscon_vte *vte);
|
||||
|
||||
void kmscon_vte_bind(struct kmscon_vte *vte, struct kmscon_console *con);
|
||||
void kmscon_vte_input(struct kmscon_vte *vte, kmscon_symbol_t ch);
|
||||
void kmscon_vte_resize(struct kmscon_vte *vte);
|
||||
|
||||
void kmscon_vte_input(struct kmscon_vte *vte, struct kmscon_input_event *ev);
|
||||
void kmscon_vte_putc(struct kmscon_vte *vte, kmscon_symbol_t ch);
|
||||
|
||||
#endif /* KMSCON_VTE_H */
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "eloop.h"
|
||||
#include "input.h"
|
||||
@ -48,6 +49,7 @@ struct app {
|
||||
struct kmscon_eloop *eloop;
|
||||
struct kmscon_signal *sig_term;
|
||||
struct kmscon_signal *sig_int;
|
||||
struct kmscon_signal *sig_chld;
|
||||
struct kmscon_symbol_table *st;
|
||||
struct kmscon_font_factory *ff;
|
||||
struct kmscon_compositor *comp;
|
||||
@ -63,17 +65,68 @@ static void sig_term(struct kmscon_signal *sig, int signum, void *data)
|
||||
terminate = 1;
|
||||
}
|
||||
|
||||
static void sig_chld(struct kmscon_signal *sig, int signum, void *data)
|
||||
{
|
||||
pid_t pid;
|
||||
int status;
|
||||
|
||||
/*
|
||||
* If multiple children exit at the same time, signalfd would put them
|
||||
* all in one event. So we reap in a loop.
|
||||
*/
|
||||
while (1) {
|
||||
pid = waitpid(-1, &status, WNOHANG);
|
||||
if (pid == -1) {
|
||||
if (errno != ECHILD)
|
||||
log_warning("vte: cannot wait on child: %m\n");
|
||||
break;
|
||||
} else if (pid == 0) {
|
||||
break;
|
||||
} else if (WIFEXITED(status)) {
|
||||
if (WEXITSTATUS(status) != 0)
|
||||
log_info("vte: child %d exited with status "
|
||||
"%hd\n", pid, WEXITSTATUS(status));
|
||||
else
|
||||
log_debug("vte: child %d exited "
|
||||
"successfully\n", pid);
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
log_debug("vte: child %d exited by signal %d\n", pid,
|
||||
WTERMSIG(status));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void terminal_closed(struct kmscon_terminal *term, void *data)
|
||||
{
|
||||
#if 0
|
||||
/*
|
||||
* Alternativly, we could spwan a new login/shell here, like what
|
||||
* happens when the user exits the shell in a linux console:
|
||||
*/
|
||||
|
||||
int ret;
|
||||
struct app *app = data;
|
||||
|
||||
if (!app)
|
||||
goto err_out;
|
||||
|
||||
ret = kmscon_terminal_open(app->term, app->eloop,
|
||||
terminal_closed, app);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
return;
|
||||
|
||||
err_out:
|
||||
#endif
|
||||
terminate = 1;
|
||||
}
|
||||
|
||||
static void read_input(struct kmscon_input *input,
|
||||
struct kmscon_input_event *ev, void *data)
|
||||
{
|
||||
struct app *app = data;
|
||||
kmscon_symbol_t ch;
|
||||
|
||||
if (ev->unicode == KMSCON_INPUT_INVALID)
|
||||
return;
|
||||
|
||||
ch = kmscon_symbol_make(ev->unicode);
|
||||
kmscon_terminal_input(app->term, ch);
|
||||
kmscon_terminal_input(app->term, ev);
|
||||
}
|
||||
|
||||
static void activate_outputs(struct app *app)
|
||||
@ -131,6 +184,7 @@ static void destroy_app(struct app *app)
|
||||
kmscon_compositor_unref(app->comp);
|
||||
kmscon_font_factory_unref(app->ff);
|
||||
kmscon_symbol_table_unref(app->st);
|
||||
kmscon_eloop_rm_signal(app->sig_chld);
|
||||
kmscon_eloop_rm_signal(app->sig_int);
|
||||
kmscon_eloop_rm_signal(app->sig_term);
|
||||
kmscon_eloop_unref(app->eloop);
|
||||
@ -154,6 +208,11 @@ static int setup_app(struct app *app)
|
||||
if (ret)
|
||||
goto err_loop;
|
||||
|
||||
ret = kmscon_eloop_new_signal(app->eloop, &app->sig_chld, SIGCHLD,
|
||||
sig_chld, NULL);
|
||||
if (ret)
|
||||
goto err_loop;
|
||||
|
||||
ret = kmscon_symbol_table_new(&app->st);
|
||||
if (ret)
|
||||
goto err_loop;
|
||||
@ -186,7 +245,8 @@ static int setup_app(struct app *app)
|
||||
if (ret)
|
||||
goto err_loop;
|
||||
|
||||
ret = kmscon_terminal_connect_eloop(app->term, app->eloop);
|
||||
ret = kmscon_terminal_open(app->term, app->eloop,
|
||||
terminal_closed, app);
|
||||
if (ret)
|
||||
goto err_loop;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user