summaryrefslogtreecommitdiffstats
path: root/terminal.c
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@redhat.com>2008-12-07 23:17:31 -0500
committerKristian Høgsberg <krh@redhat.com>2008-12-07 23:17:31 -0500
commit269d6e3daf70e13c2e774c64decb7c33a1420b47 (patch)
treea74179829177756c75117f067e8dcb878cde8919 /terminal.c
parent44e3c5e1ad795a4405f8f0147fddd3afce34b518 (diff)
downloadwayland-269d6e3daf70e13c2e774c64decb7c33a1420b47.tar.gz
wayland-269d6e3daf70e13c2e774c64decb7c33a1420b47.tar.xz
wayland-269d6e3daf70e13c2e774c64decb7c33a1420b47.zip
Run command in a pty and feed output to wayland terminal.
Diffstat (limited to 'terminal.c')
-rw-r--r--terminal.c97
1 files changed, 88 insertions, 9 deletions
diff --git a/terminal.c b/terminal.c
index 0ecb304..acd4f2b 100644
--- a/terminal.c
+++ b/terminal.c
@@ -28,6 +28,7 @@
#include <unistd.h>
#include <math.h>
#include <time.h>
+#include <pty.h>
#include <cairo.h>
#include <glib.h>
@@ -48,9 +49,10 @@ struct terminal {
struct wl_display *display;
int resize_scheduled;
char *data;
- int width, height;
+ int width, height, tail, row, column;
int fd;
struct buffer *buffer;
+ GIOChannel *channel;
};
static void
@@ -60,7 +62,7 @@ terminal_draw_contents(struct terminal *terminal)
cairo_surface_t *surface;
cairo_t *cr;
cairo_font_extents_t extents;
- int i;
+ int i, line;
window_get_child_rectangle(terminal->window, &rectangle);
@@ -76,11 +78,13 @@ terminal_draw_contents(struct terminal *terminal)
cairo_select_font_face (cr, "mono",
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size(cr, 14);
cairo_font_extents(cr, &extents);
for (i = 0; i < terminal->height; i++) {
+ line = (terminal->tail + i) % terminal->height;
cairo_move_to(cr, 0, extents.ascent + extents.height * i);
- cairo_show_text(cr, &terminal->data[i * (terminal->width + 1)]);
+ cairo_show_text(cr, &terminal->data[line * (terminal->width + 1)]);
}
cairo_destroy(cr);
@@ -132,16 +136,47 @@ acknowledge_handler(struct window *window, uint32_t key, void *data)
terminal->resize_scheduled = 0;
}
+static void
+terminal_data(struct terminal *terminal, const char *data, size_t length)
+{
+ int i;
+ char *row;
+
+ for (i = 0; i < length; i++) {
+ row = &terminal->data[terminal->row * (terminal->width + 1)];
+ switch (data[i]) {
+ case '\r':
+ terminal->column = 0;
+ break;
+ case '\n':
+ terminal->row++;
+ terminal->column = 0;
+ if (terminal->row == terminal->height)
+ terminal->row = 0;
+ break;
+ case '\t':
+ memset(&row[terminal->column], ' ', -terminal->column & 7);
+ terminal->column = (terminal->column + 7) & ~7;
+ break;
+ default:
+ if (terminal->column < terminal->width)
+ row[terminal->column++] = data[i];
+ break;
+ }
+ }
+}
+
static struct terminal *
terminal_create(struct wl_display *display, int fd)
{
struct terminal *terminal;
- int size, i;
+ int size;
terminal = malloc(sizeof *terminal);
if (terminal == NULL)
return terminal;
+ memset(terminal, 0, sizeof *terminal);
terminal->fd = fd;
terminal->window = window_create(display, fd, "Wayland Terminal",
500, 100, 500, 400);
@@ -153,17 +188,60 @@ terminal_create(struct wl_display *display, int fd)
terminal->data = malloc(size);
memset(terminal->data, 0, size);
- for (i = 0; i < terminal->height; i++) {
- snprintf(&terminal->data[i * (terminal->width + 1)], terminal->width,
- "hello world, line %d", i);
- }
-
window_set_resize_handler(terminal->window, resize_handler, terminal);
window_set_acknowledge_handler(terminal->window, acknowledge_handler, terminal);
return terminal;
}
+static gboolean
+io_handler(GIOChannel *source,
+ GIOCondition condition,
+ gpointer data)
+{
+ struct terminal *terminal = data;
+ gchar buffer[256];
+ gsize bytes_read;
+ GError *error = NULL;
+
+ g_io_channel_read_chars(source, buffer, sizeof buffer,
+ &bytes_read, &error);
+ printf("got data: %.*s\n", bytes_read, buffer);
+
+ terminal_data(terminal, buffer, bytes_read);
+
+ if (!terminal->resize_scheduled) {
+ g_idle_add(idle_redraw, terminal);
+ terminal->resize_scheduled = 1;
+ }
+
+ return TRUE;
+}
+
+static int
+terminal_run(struct terminal *terminal, const char *path)
+{
+ int master, slave;
+ pid_t pid;
+
+ pid = forkpty(&master, NULL, NULL, NULL);
+ if (pid == 0) {
+ close(master);
+ if (execl(path, path, NULL)) {
+ printf("exec failed: %m\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ close(slave);
+ terminal->channel = g_io_channel_unix_new(master);
+ fcntl(master, F_SETFL, O_NONBLOCK);
+ g_io_add_watch(terminal->channel, G_IO_IN,
+ io_handler, terminal);
+
+ return 0;
+}
+
int main(int argc, char *argv[])
{
struct wl_display *display;
@@ -189,6 +267,7 @@ int main(int argc, char *argv[])
g_source_attach(source, NULL);
terminal = terminal_create(display, fd);
+ terminal_run(terminal, "/bin/bash");
terminal_draw(terminal);
g_main_loop_run(loop);